diff --git a/center/center.py b/center/center.py new file mode 100644 index 0000000..523efd7 --- /dev/null +++ b/center/center.py @@ -0,0 +1,162 @@ +from flask import Flask, request, jsonify +from werkzeug.utils import secure_filename +from datetime import datetime +import os +from game.service.searchService import getPlacesFromWeb, getUrlsFromWeb # 通过外部搜索得到资料的urls和松江大学城的places +from game.service.searchService import getAroud_smallplace_On_bigPlace +from game.service.ImageService import getTraitsFrom_Images, getTraitsFrom_Image # 业务实现类:得到图像特征 +from game.compute.compute_similarity import calculate_embedding_cosine_similarity, \ + calculate_tfidf_cosine_similarity # 计算特征之间的相似度 +from flask_cors import CORS +from gevent import pywsgi +import shutil # 导入 shutil 模块用于文件操作 +import tempfile +import json +from game.utils.similarity_read import write_top_similarities_to_file # 将相似度top-3的信息写入文件 +from game.model.modeljudge import judge_byModel # 进行特征的最后决策 +from game.utils.process_set_tolist import convert_sets_to_lists # 将set数据转为list数据 +from game.tts.text_to_video import generate_audio # 根据文本生成音频 + +app = Flask(__name__) +# app.json.ensure_ascii = False # 解决中文乱码问题 +app.config['JSON_AS_ASCII'] = False +CORS(app, resources={r"/*": {"origins": "*"}}) + +# 环境配置 +app.config['UPLOAD_FOLDER'] = 'uploads' # 确保这个文件夹存在或在代码中创建它 +app.config['UPLOAD_FOLDER'] = 'image_temp' +# API密钥配置 +os.environ["DASHSCOPE_API_KEY"] = "sk-d07d9d5c4d8d4158abbaf45a40c10042" +save_path = '..//tempfile//' + +if not os.path.exists(app.config['UPLOAD_FOLDER']): + os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) + + +# 上传图像和问题得到响应 +@app.route('/upload', methods=['POST']) +def upload_file(): + print("你好呀~") + # 1.上传文件模块 + if 'file' not in request.files: + return jsonify({"error": "No file part"}), 400 + file = request.files['file'] + if file.filename == '': + return jsonify({"error": "No selected file"}), 400 + if not file.filename.lower().endswith(('.png', '.jpg', '.jpeg')): + return jsonify({"error": "File not supported"}), 400 + + original_filename = secure_filename(file.filename) + timestamp_ms = int(datetime.now().timestamp() * 1000) + filename = f"{timestamp_ms}_{original_filename}" + original_file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + + # 再次确认目录存在 + if not os.path.exists(app.config['UPLOAD_FOLDER']): + os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) + file.save(original_file_path) + + # 创建新的文件路径 + new_filename = f"processed_{filename}" + new_file_path = os.path.join(app.config['UPLOAD_FOLDER'], new_filename) + + # 复制文件到新路径 + shutil.copy(original_file_path, new_file_path) + print(f"临时文件名:{new_filename}") + print(f"临时文件URL:{new_file_path}") + + # 1.4.获取用户提问 + user_question = request.form['question'] + print("用户问题:", user_question) + + # 2.得到主图像特征 + main_traits = getTraitsFrom_Image(new_file_path) + print("该图像的特征如下:", main_traits) # 【1.主图特征】 + + # 3.首先获取松江大学城内的地标建筑物,缩小范围 + first_question = "上海市松江区松江大学城内有哪些建筑物?" + urls_from_web = getUrlsFromWeb(first_question) # 通过外部搜索得到关于question的urls集合 # 【2.参考文献】 + songjiang_places = getPlacesFromWeb(first_question) # 得到松江大学城里的建筑物集合 # 【3.附近地点】 + + big_places_dict = {} # 初始化一个大集合big_places_dict,元素为每一个bigplace + max_similarities = [] # 初始设置为-1,得到最大相似度 + small_names = [] + small_name_photos = {} + + # 4.计算得到相似度最高的小地标名称 + for big_place in songjiang_places: # 【3.大地点】 + small_names, small_name_photos = getAroud_smallplace_On_bigPlace(big_place) # 得到小地标的名称和小地标的图片集合 + + # 为当前大地标创建一个字典来存储每个小地标及其与主图像的相似度 + small_places = {} + + for small_name, small_photos in small_name_photos.items(): + print(f"{small_name}:{small_photos}") # 【4.大地点的小地点】 + if not small_photos: + print(f"{small_name} 没有可用的照片,跳过此地标") + continue + try: + small_traits = getTraitsFrom_Images(small_photos) # 得到小地标的图像特征 + print(f"{small_name}的地图特征为:{small_traits}") + small_and_main_similarity = calculate_embedding_cosine_similarity(main_traits, small_traits) + print(f"{small_name}与图像特征的相似度为:{small_and_main_similarity}") + small_places[small_name] = small_traits + except Exception as e: + print(f"处理 {small_name} 的图像时发生错误: {e}") + continue # 遇到错误时跳过此地标 + + # 更新整体最高相似度列表及其对应的小地标名称、特征及大地标 + max_similarities.append((small_name, small_and_main_similarity, big_place, small_traits)) + + # 将当前大地标及其所有小地标的相似度信息存入字典 + big_places_dict[big_place] = small_places + + # 5.对相似度列表按照相似度值进行降序排序 + max_similarities.sort(key=lambda x: x[1], reverse=True) + + # 6.只取前三个 + top_3_similarities = max_similarities[:3] + + # 打印所有地标中相似度最高的三个小地标信息 + if top_3_similarities: + for idx, (small_name, similarity, big_place, traits) in enumerate(top_3_similarities, 1): + print(f"第{idx}名:小地标是:{small_name},位于大地标 {big_place},相似度为:{similarity},特征为:{traits}") + + # 7.将前三个相似度最高的地标信息及其特征写入临时文件 + top3_file = write_top_similarities_to_file(top_3_similarities, save_path) + + # 9.给到决策大模型进行参考,得到最后的answer + judge_content = judge_byModel(main_traits, top3_file) + print(f"最后决策:{judge_content}") + + # 10.根据JudgeContent内容生成音频 + video_path = generate_audio(judge_content) + print(f"音频路径:{video_path}") + + # 11.返回相似度最高的前三个地标信息,按相似度排序后标上序号 + response = [ + { + "rank": idx, # 直接使用 idx,因为 enumerate 从 1 开始 + "small_place": small_name, + "big_place": big_place, + "similarity": similarity, + "traits": convert_sets_to_lists(traits) + } + for idx, (small_name, similarity, big_place, traits) in enumerate(top_3_similarities, start=1) + ] + + return jsonify({ + "main_traits": convert_sets_to_lists(main_traits), # 传入图像的特征 + "first_question": first_question, # 问题 + "candidate_big_places": convert_sets_to_lists(songjiang_places), # 得到松江大学城里的大地点集合 + "search_around_traits": convert_sets_to_lists(big_places_dict), # 大地点下面的小地点特征 + "candidate": convert_sets_to_lists(response), # 候选地点和特征 + "judge_content": judge_content, # 最后的决策 + "video_path": video_path # 音频路径 + }) + + +if __name__ == '__main__': + app.debug = True + server = pywsgi.WSGIServer(('0.0.0.0', 8081), app) + server.serve_forever() diff --git a/compute/compute_similarity.py b/compute/compute_similarity.py new file mode 100644 index 0000000..4cb993f --- /dev/null +++ b/compute/compute_similarity.py @@ -0,0 +1,71 @@ +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.metrics.pairwise import cosine_similarity # 导入余弦相似度函数 +from game.utils.process_image_traits import get_trait_embedding # 得到特征文本的向量 +import numpy as np + +""" +1.通过TF-IDF计算词频的方式来计算text1和text2之间的相似度 +""" + + +def calculate_tfidf_cosine_similarity(text1, text2): + vectorizer = TfidfVectorizer() + corpus = [text1, text2] + vectors = vectorizer.fit_transform(corpus) + similarity = cosine_similarity(vectors) + return similarity[0][1] # 返回第一个文本和第二个文本之间的相似度 + + +""" +2.计算text1和text2的相似度 +""" + + +def calculate_embedding_cosine_similarity(text1, text2): + # 1.得到文本的向量 + embedding1 = get_trait_embedding(text1) + embedding2 = get_trait_embedding(text2) + # 2.将列表转换为numpy数组,方便执行向量操作 + vec1 = np.array(embedding1) + vec2 = np.array(embedding2) + + # 3.计算两个向量的点积 + dot_product = np.dot(vec1, vec2) + + # 4.计算两个向量的欧几里得范数【即表示向量的长度和大小】 + norm_vec1 = np.linalg.norm(vec1) + norm_vec2 = np.linalg.norm(vec2) + + # 5.计算余弦相似度 + cosine_sim = dot_product / (norm_vec1 * norm_vec2) + + # 6.返回保留六位小数的结果 + return round(cosine_sim, 6) + + +# # 示例 +text1 = """'1. **建筑风格**: + - 这些建筑具有独特的几何形状,尤其是三角形和多边形的结构。 + - 建筑物的外观设计独特,可能是由玻璃和混凝土等材料构成。 + +2. **环境**: + - 周围有绿化带和树木。 + - 有水体和桥梁。 + +3. **地理位置**: + - 这些建筑位于一个较大的区域,周围有其他建筑物和设施。 + - 远处可以看到山脉。'""" + +text2 = """1. **建筑风格**: + - 图像中的建筑具有独特的几何形状,主要由三角形和多边形构成,呈现出现代主义和未来主义的风格。 + - 建筑物的设计独特,具有明显的尖顶和斜面,给人一种科技感和创新感。 + +2. **环境**: + - 建筑周围有广阔的绿地和水体,环境优美,绿化覆盖率高。 + - 建筑物周围有道路和桥梁,交通便利,周围还有其他建筑物和设施,形成一个完整的区域。 + +3. **地理位置**: + - 建筑位于一个城市或大学校园内,周围有其他建筑物和设施,表明这是一个有人居住和活动的区域。 + - 建筑物的地理位置可能是一个重要的地标或文化中心,吸引了大量的游客和参观者。""" +similar_points = calculate_embedding_cosine_similarity(text1, text2) +print("相似度:", similar_points) diff --git a/demo/ImageUnderstanding.py b/demo/ImageUnderstanding.py new file mode 100644 index 0000000..ff68e31 --- /dev/null +++ b/demo/ImageUnderstanding.py @@ -0,0 +1,164 @@ +import _thread as thread +import base64 +import datetime +import hashlib +import hmac +import json +from urllib.parse import urlparse, urlencode +import ssl +from datetime import datetime +from time import mktime +from wsgiref.handlers import format_date_time +import websocket + +# 定义API凭证变量 +appid = "2ef09001" # APPID +api_secret = "YTViOGRlNDUxYzUxNGQ1YzBiMjY1OTc4" # APISecret +api_key = "8a8b0b84743a48f15f9ffd96d962a024" # APIKey +imagedata = open("SUES03.png", 'rb').read() # 打开并读取图片文件 + +# 设置图像理解服务的WebSocket URL +imageunderstanding_url = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image" +# 将图像数据编码为base64格式 +image_base64 = str(base64.b64encode(imagedata), 'utf-8') + +class Ws_Param: + """用于管理WebSocket连接参数的类""" + def __init__(self, appid, api_key, api_secret, imageunderstanding_url): + self.appid = appid + self.api_key = api_key + self.api_secret = api_secret + self.host = urlparse(imageunderstanding_url).netloc # 解析URL获取主机名 + self.path = urlparse(imageunderstanding_url).path # 解析URL获取路径 + self.image_understanding_url = imageunderstanding_url + + def create_url(self): + """创建带有认证信息的URL""" + now = datetime.now() + date = format_date_time(mktime(now.timetuple())) # 获取格式化的时间 + signature_origin = f"host: {self.host}\ndate: {date}\nGET {self.path} HTTP/1.1" + signature_sha = hmac.new(self.api_secret.encode('utf-8'), signature_origin.encode('utf-8'), hashlib.sha256).digest() # HMAC-SHA256签名 + signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8') # 对签名进行Base64编码 + authorization_origin = (f'api_key="{self.api_key}", algorithm="hmac-sha256", headers="host date request-line", ' + f'signature="{signature_sha_base64}"') + authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8') # 对整个授权头进行Base64编码 + auth_params = { + "authorization": authorization, + "date": date, + "host": self.host + } + return self.image_understanding_url + '?' + urlencode(auth_params) # 创建完整的URL + +class WebSocketHandler: + """用于处理WebSocket通信的类""" + def __init__(self, appid, messages): + self.appid = appid + self.messages = messages + self.answer = "" + + def on_error(self, ws, error): + """WebSocket发生错误时调用""" + print("错误:", error) + + def on_close(self, ws, one=None, two=None): + """WebSocket关闭时调用""" + print("\n连接已关闭") + + def on_open(self, ws): + """WebSocket连接成功开启时调用""" + thread.start_new_thread(self.run, (ws,)) + + def run(self, ws): + """在WebSocket连接开启后执行发送消息的操作""" + data = json.dumps(self.gen_params(self.appid, self.messages)) + ws.send(data) + + def on_message(self, ws, message): + """接收到WebSocket消息时调用""" + data = json.loads(message) + code = data['header']['code'] + if code != 0: + print(f'请求错误: {code}, {data}') + ws.close() + else: + choices = data["payload"]["choices"] + status = choices["status"] + content = choices["text"][0]["content"] + print(content, end="") + self.answer += content + if status == 2: + ws.close() + + @staticmethod + def gen_params(appid, messages): + """生成WebSocket请求的参数""" + return { + "header": { + "app_id": appid + }, + "parameter": { + "chat": { + "domain": "image", + "temperature": 0.5, + "top_k": 4, + "max_tokens": 2028, + "auditing": "default" + } + }, + "payload": { + "message": { + "text": messages + } + } + } + +def start_websocket(appid, api_key, api_secret, imageunderstanding_url, messages): + """初始化并启动WebSocket连接""" + ws_param = Ws_Param(appid, api_key, api_secret, imageunderstanding_url) # 创建参数对象 + websocket.enableTrace(False) # 禁用WebSocket调试输出 + ws_url = ws_param.create_url() # 获取完整的WebSocket URL + + ws_handler = WebSocketHandler(appid, messages) # 创建WebSocket处理器 + ws = websocket.WebSocketApp(ws_url, + on_message=ws_handler.on_message, + on_error=ws_handler.on_error, + on_close=ws_handler.on_close, + on_open=ws_handler.on_open) + ws.appid = appid + ws.messages = messages + ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) # 启动WebSocket,使用不验证证书的SSL选项 + +if __name__ == '__main__': + prompt = """ +请对提供的图像进行分析,关注以下要点: + +1. **设计风格**: + - 描述建筑或风景的主要设计特点。 + - 讨论其可能的文化或历史联系。 + +2. **具体特征与位置关系**: + - 描述图像中显著事物的特征。 + - 推测其可能的地理位置。 + +3. **环境描述**: + - 描述自然与人造元素。 + - 分析这些元素如何影响场景。 + +4. **文字与标志**: + - 描述可见的文字或标志。 + - 推测其含义。 + +5. **人物活动**: + - 描述人物的活动。 + - 分析其与环境的关系。 + +请直接、简洁地回答,避免不必要的修饰。 +""" + + # 将图像数据和提示组合成消息列表 + messages = [ + {"role": "user", "content": image_base64, "content_type": "image"}, + {"role": "user", "content": prompt, "content_type": "text"} + ] + print("回答:", end="") + start_websocket(appid, api_key, api_secret, imageunderstanding_url, messages) # 启动WebSocket并发送消息 diff --git a/demo/ReActBase.py b/demo/ReActBase.py new file mode 100644 index 0000000..bd7fc0b --- /dev/null +++ b/demo/ReActBase.py @@ -0,0 +1,24 @@ +import os +from langchain.agents import load_tools +from langchain.agents import initialize_agent +from langchain.agents import AgentType +from langchain_community.llms import Tongyi + +# 设置API密钥 +os.environ["SERPAPI_API_KEY"] = "31a3c96f0ce535fd1b43117d3c9298c66753b6dae1da9074708f03ecc8282367" +os.environ["DASHSCOPE_API_KEY"] = "sk-d07d9d5c4d8d4158abbaf45a40c10042" + +# 导入所需的库和模型 +DASHSCOPE_API_KEY = "sk-d07d9d5c4d8d4158abbaf45a40c10042" +llm = Tongyi(dashscope_api_key="sk-d07d9d5c4d8d4158abbaf45a40c10042", model="qwen-plus") + +# 加载工具 +tools = load_tools(["serpapi"], llm=llm) + +# 初始化代理 +agent = initialize_agent(tools, llm, agent=AgentType.SELF_ASK_WITH_SEARCH, verbose=True) + +# 运行代理 +response = agent.run( + "假设你是一个特征分析师,你能够根据特征分析出具体位置,请根据以下特征告诉我具体地址?(确定具体地理位置。比如:xxx学校的xx教学楼、xxx学校的xxx图书馆、xxx地区的xxx办公楼、xxx地区的xxx餐厅、xxx地区的xxx娱乐城等等。注意:回复不能模棱两可,不能回复自己不知道,需要根据以下特征坚定的回答一处地方,并逐步思考)前提:该具体位置位于上海市松江大学城的某处地方,1. 建筑设计:该建筑物的整体外形设计为独特的M型结构,墙体颜色为白色,给人一种现代和前卫的感觉。这种设计可能意味着该建筑是为了某种特定的功能或目的而建,如艺术展览、会议中心或其他公共设施。 2. 玻璃幕墙:从图片中可以看到,建筑物的一部分使用了大面积的玻璃幕墙。这可能意味着内部空间需要充足的自然光,或者是为了展示外部景观。 3. 周围环境:该建筑位于一个开阔的区域,前面有一个湖泊或大型池塘。湖边有绿色的草坪和树木,为这个区域提供了一个宁静的环境。此外,远处还有一些低矮的建筑和道路,暗示该地点可能是城市中的一个公园或休闲区。 4. 天气:天空是晴朗的蓝色,没有云彩,说明这是一个好天气的日子。这样的天气可能会吸引许多人到这个地方游玩或进行户外活动。 5. 具体位置在上海市江大学城的某处地方 ") +print(response) diff --git a/demo/ReActByBC.py b/demo/ReActByBC.py new file mode 100644 index 0000000..1594ac4 --- /dev/null +++ b/demo/ReActByBC.py @@ -0,0 +1,56 @@ +import os +import requests +from langchain_community.agent_toolkits.load_tools import load_tools +from langchain.agents import initialize_agent, AgentType +from langchain_core.runnables import Runnable + +# 自定义模型类,用于与 SiliconFlow API 通信,继承 Runnable +class SiliconFlowModel(Runnable): + def __init__(self, api_url, api_key): + self.api_url = api_url + self.api_key = api_key + + def invoke(self, messages): + payload = { + "model": "internlm/internlm2_5-7b-chat", + "messages": [{"role": "user", "content": messages}], + "max_tokens": 512, + "temperature": 0.7, + "top_p": 0.7, + "stream": False + } + headers = { + "accept": "application/json", + "content-type": "application/json", + "authorization": f"Bearer {self.api_key}" + } + response = requests.post(self.api_url, json=payload, headers=headers) + response_json = response.json() + return response_json.get("choices", [{}])[0].get("message", {}).get("content", "") + +# 设置 API Keys +# os.environ["DASHSCOPE_API_KEY"] = '替换为你的DASHSCOPE_API_KEY' +os.environ["SERPAPI_API_KEY"] = '31a3c96f0ce535fd1b43117d3c9298c66753b6dae1da9074708f03ecc8282367' + +# 初始化 SiliconFlow 模型 +silicon_model = SiliconFlowModel( + api_url="https://api.siliconflow.example/v1/models", + api_key="kifqepgmrmlstabhxlmxrylkppvcppumtvwcdbwajgotuvvk" +) + +# 加载工具 +tools = load_tools(["serpapi"], llm=silicon_model) + +# 初始化代理,使用 SiliconFlowModel +agent = initialize_agent( + tools=tools, + llm=silicon_model, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=True +) + +# 使用 agent 执行任务 +response = agent.run("今天星期几?历史上的今天发生了哪些大事?") + +# 打印结果 +print(response) diff --git a/demo/ReActFromSera.py b/demo/ReActFromSera.py new file mode 100644 index 0000000..80a266f --- /dev/null +++ b/demo/ReActFromSera.py @@ -0,0 +1,75 @@ +import os +import requests +from langchain.agents import initialize_agent, AgentType +from langchain.agents import load_tools +from langchain_core.runnables import Runnable +from langchain_community.llms import Tongyi + +# 自定义模型类,用于与 SiliconFlow API 通信,继承 Runnable +class SiliconFlowModel(Runnable): + def __init__(self, api_url, api_key): + self.api_url = api_url + self.api_key = api_key + + # 修改 invoke 方法,添加 *args 和 **kwargs 捕获所有额外参数 + def invoke(self, messages, *args, **kwargs): + # 检查消息是否是 StringPromptValue,如果是,则转换为字符串 + if isinstance(messages, StringPromptValue): + messages = str(messages) # 将 StringPromptValue 转换为字符串 + + payload = { + "model": "internlm/internlm2_5-7b-chat", + "messages": [{"role": "user", "content": messages}], # 确保 messages 是字符串 + "max_tokens": 512, + "temperature": 0.7, + "top_p": 0.7, + "stream": False + } + + + headers = { + "accept": "application/json", + "content-type": "application/json", + "authorization": f"Bearer {self.api_key}" + } + + response = requests.post(self.api_url, json=payload, headers=headers) + response_json = response.json() + + # 处理生成结果 + result = response_json.get("choices", [{}])[0].get("message", {}).get("content", "") + + # 如果 kwargs 中有 stop 参数,处理截断逻辑 + stop = kwargs.get('stop', None) + if stop: + for token in stop: + result = result.split(token)[0] + + return result + +# 设置 API Keys +# os.environ["DASHSCOPE_API_KEY"] = '替换为你的DASHSCOPE_API_KEY' +os.environ["SERPAPI_API_KEY"] = '31a3c96f0ce535fd1b43117d3c9298c66753b6dae1da9074708f03ecc8282367' + +# 初始化 SiliconFlow 模型 +silicon_model = SiliconFlowModel( + api_url="https://api.siliconflow.example/v1/models", + api_key="sk-kifqepgmrmlstabhxlmxrylkppvcppumtvwcdbwajgotuvvk" +) + +# 加载工具 +tools = load_tools(["serpapi"], llm=silicon_model) + +# 初始化代理,使用 SiliconFlowModel +agent = initialize_agent( + tools=tools, + llm=silicon_model, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=True +) + +# 使用 agent 执行任务 +response = agent.run("今天星期几?历史上的今天发生了哪些大事?".__str__) + +# 打印结果 +print(response) diff --git a/demo/TongyiModelFromOpen.py b/demo/TongyiModelFromOpen.py new file mode 100644 index 0000000..4f8de2d --- /dev/null +++ b/demo/TongyiModelFromOpen.py @@ -0,0 +1,31 @@ +import os +from langchain import SerpAPIWrapper +from langchain.agents import initialize_agent, Tool +from langchain.agents import AgentType +from langchain_community.llms import Tongyi + +# 设置API密钥 +os.environ["SERPAPI_API_KEY"] = "31a3c96f0ce535fd1b43117d3c9298c66753b6dae1da9074708f03ecc8282367" +os.environ["DASHSCOPE_API_KEY"] = "sk-d07d9d5c4d8d4158abbaf45a40c10042" + +# 导入所需的库和模型 +DASHSCOPE_API_KEY = "sk-d07d9d5c4d8d4158abbaf45a40c10042" +llm = Tongyi(dashscope_api_key = "sk-d07d9d5c4d8d4158abbaf45a40c10042", model = "qwen-plus") + +search = SerpAPIWrapper() +tools = [ + Tool( + name="Intermediate Answer", + func=search.run, + description="useful for when you need to ask with search", + ) +] + +self_ask_with_search = initialize_agent( + tools, llm, agent=AgentType.SELF_ASK_WITH_SEARCH, verbose=True +) +result = self_ask_with_search.run( + "假设你是一个特征分析师,你能够根据特征分析出具体位置,请根据以下特征告诉我具体地址?(确定具体地理位置。比如:xxx学校的xx教学楼、xxx学校的xxx图书馆、xxx地区的xxx办公楼、xxx地区的xxx餐厅、xxx地区的xxx娱乐城等等。注意:回复不能模棱两可,不能回复自己不知道,需要根据以下特征坚定的回答一处地方,并逐步思考)前提:该具体位置位于上海市松江大学城的某处地方,1. 建筑设计:该建筑物的整体外形设计为独特的M型结构,墙体颜色为白色,给人一种现代和前卫的感觉。这种设计可能意味着该建筑是为了某种特定的功能或目的而建,如艺术展览、会议中心或其他公共设施。 2. 玻璃幕墙:从图片中可以看到,建筑物的一部分使用了大面积的玻璃幕墙。这可能意味着内部空间需要充足的自然光,或者是为了展示外部景观。 3. 周围环境:该建筑位于一个开阔的区域,前面有一个湖泊或大型池塘。湖边有绿色的草坪和树木,为这个区域提供了一个宁静的环境。此外,远处还有一些低矮的建筑和道路,暗示该地点可能是城市中的一个公园或休闲区。 4. 天气:天空是晴朗的蓝色,没有云彩,说明这是一个好天气的日子。这样的天气可能会吸引许多人到这个地方游玩或进行户外活动。 5. 具体位置在上海市江大学城的某处地方 " +) + +print(result) \ No newline at end of file diff --git a/image/SUES03 (1).png b/image/SUES03 (1).png new file mode 100644 index 0000000..08ffcc9 Binary files /dev/null and b/image/SUES03 (1).png differ diff --git a/image/sues01.png b/image/sues01.png new file mode 100644 index 0000000..30889aa Binary files /dev/null and b/image/sues01.png differ diff --git a/image/sues02.png b/image/sues02.png new file mode 100644 index 0000000..b34bba1 Binary files /dev/null and b/image/sues02.png differ diff --git a/mapSearch/aroudplaces.py b/mapSearch/aroudplaces.py new file mode 100644 index 0000000..0ae6d15 --- /dev/null +++ b/mapSearch/aroudplaces.py @@ -0,0 +1,53 @@ +import requests +from game.utils.process_map_data import extract_poi_names_and_photos + +""" + 1.调用高德地图API的文本搜索接口,获取指定地点信息。 + + 参数: + keywords (str): 查询的关键字,例如 "北京大学"。 + city (str): 城市名称,例如 "beijing"。 + key (str): 高德地图的API密钥。 + types (str): 查询POI类型,可选,默认为None。 + citylimit (bool): 是否限制返回结果为指定城市,默认为False。 + offset (int): 每页结果数,强烈建议不超过25,默认为20。 + page (int): 当前页数,默认为1。 + extensions (str): 返回结果控制,默认为'all'。 + + 返回: + dict: API返回的结果,包含地点的详细信息。 + """ +def amap_place_search(keywords, city=None, types=None, citylimit=False, offset=20, page=1, extensions='all'): + + base_url = "https://restapi.amap.com/v3/place/text" + + # 请求参数 + params = { + "keywords": keywords, + "city": city, + "key": "04708221844d5c25b001370f52a83791", + "types": types, + "citylimit": "true" if citylimit else "false", + "offset": offset, + "page": page, + "extensions": extensions + } + + # 发送GET请求 + response = requests.get(base_url, params=params) + + # 判断请求是否成功 + if response.status_code == 200: + return response.json() # 返回JSON格式的响应 + else: + return {"error": f"请求失败,状态码: {response.status_code}"} + + +# 示例使用 +if __name__ == "__main__": + keywords = "上海工程技术大学(松江)" + + result = amap_place_search(keywords) + names_set, name_photos_dict, all_photos_set = extract_poi_names_and_photos(result) # 返回上海工程技术大学周围的地标 + print("\n" + keywords + "附近的地点为:", names_set) + print("\n" + keywords + "附近的地点为的图片为:", name_photos_dict) diff --git a/model/modelVL.py b/model/modelVL.py new file mode 100644 index 0000000..36702cf --- /dev/null +++ b/model/modelVL.py @@ -0,0 +1,154 @@ +from openai import OpenAI +import os +from game.utils.image_read import encode_image + +# 设置环境变量,存储 API 密钥 +os.environ["DASHSCOPE_API_KEY"] = "sk-d07d9d5c4d8d4158abbaf45a40c10042" + +""" +1.通过tongyi-VL识别图像位置 +""" + + +def get_image_place(image_path, user_question): + base64_image = encode_image(image_path) + client = OpenAI( + api_key="sk-d07d9d5c4d8d4158abbaf45a40c10042", + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", + ) + completion = client.chat.completions.create( + model="qwen-vl-max-0809", + messages=[ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{base64_image}" + } + }, + { + "type": "text", + "text": user_question + } + ] + } + ] + ) + print(completion.model_dump_json()) # 如果你需要以 JSON 格式打印输出,这里假设方法名正确 + return completion.model_dump_json() + + +""" +2.通过tongyi-VL识别图像特征 +""" + + +def get_image_traits(image_path): + base64_image = encode_image(image_path) + client = OpenAI( + api_key="sk-d07d9d5c4d8d4158abbaf45a40c10042", + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", + ) + completion = client.chat.completions.create( + model="qwen-vl-max-0809", + messages=[ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{base64_image}" + } + }, + { + "type": "text", + "text": "假设你是图像特征提取小助手,已知传入的图像来自上海市松江大学城的某处地方,请帮我总结上述图像的特征【只需要阐述图像的特征(包括建筑风格、环境、地理位置三个方面),无需进行过度推理。回答内容如:\n\n" + "1. **建筑风格**:\n" + " - 这些建筑具有独特的几何形状,尤其是三角形和多边形的结构。\n" + " - 建筑物的外观设计独特,可能是由玻璃和混凝土等材料构成。\n\n" + "2. **环境**:\n" + " - 周围有绿化带和树木。\n" + " - 有水体和桥梁。\n\n" + "3. **地理位置**:\n" + " - 这些建筑位于一个较大的区域,周围有其他建筑物和设施。\n" + " - 远处可以看到山脉。\n\n】" + } + ] + } + ] + ) + print(completion.model_dump_json()) # 如果你需要以 JSON 格式打印输出,这里假设方法名正确 + return completion.model_dump_json() + + +""" +3.得到其余被比较图像的特征 +""" + + +def get_other_image_traits(image_paths): + # 如果 image_paths 是空集合,则直接退出函数 + if not image_paths: + return + + # 动态生成 messages 的内容,根据 image_paths 的数量创建多个 image_url + image_messages = [] + + for image_url in image_paths: + base64_image = encode_image(image_url) + image_messages.append({ + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{base64_image}" + } + }) + + # 在最后添加文本信息 + image_messages.append({ + "type": "text", + "text": "假设你是图像特征提取小助手,已知传入的图像来自同一个地方,请帮我总结上述图像的特征【只需要阐述图像的特征(包括建筑风格、环境、地理位置三个方面),无需进行过度推理。示例:\n\n" + "1. **建筑风格**:\n" + " - xxxxxx。\n" + " - xxxx。\n\n" + "2. **环境**:\n" + " - xxxxx。\n" + " - xxxxxx。\n\n" + "3. **地理位置**:\n" + " - xxxxxx。\n" + " - xxxxxxx。\n\n】" + + }) + + # 创建 OpenAI 客户端 + client = OpenAI( + api_key="sk-d07d9d5c4d8d4158abbaf45a40c10042", + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", + ) + + # 调用 OpenAI 的 API,生成 chat completion + completion = client.chat.completions.create( + model="qwen-vl-max-0809", + messages=[ + { + "role": "user", + "content": image_messages + } + ] + ) + + # 输出 API 返回的结果 + print(completion.model_dump_json()) + return completion.model_dump_json() + + +# 示例使用997875/1000000 +if __name__ == "__main__": + image_paths = ['http://store.is.autonavi.com/showpic/0d1506fe0980cbe468095fb32ccf4023', + 'http://store.is.autonavi.com/showpic/c766361b076ce5789f2bc7cf848e2307', + 'http://store.is.autonavi.com/showpic/466f5ba72b508d7469c2f80b07dfee2f'] + # image_path = "D://Answer//python-learning//Fuction//game//sues02.png" + other_images_traits = get_other_image_traits(image_paths) + print(other_images_traits) diff --git a/model/modeljudge.py b/model/modeljudge.py new file mode 100644 index 0000000..810d752 --- /dev/null +++ b/model/modeljudge.py @@ -0,0 +1,45 @@ +import os +from langchain_community.llms import Tongyi +from langchain_core.prompts import PromptTemplate +import chardet + +# 1. 设置API密钥 +os.environ["DASHSCOPE_API_KEY"] = "sk-d07d9d5c4d8d4158abbaf45a40c10042" + +# 2. 导入所需的库和模型 +DASHSCOPE_API_KEY = "sk-d07d9d5c4d8d4158abbaf45a40c10042" +llm = Tongyi(dashscope_api_key="sk-d07d9d5c4d8d4158abbaf45a40c10042", model="qwen-plus") + +# 3. 设置template +template = """你现在扮演的是一名地址特征比较工程师,请利用传入的图片主特征{maintraits},与文件内容{filecontents}中的Small Place的Traits进行比较,分析其原因,返回特征最接近的Small Place。 + +要求: +1. 以建筑特点为主 +2. 根据文件内容返回一个你认为特征最接近的Small Place +3. 结果格式示例: + 分析:xxxxx的建筑风格与图片主特征最相近,特征为:xxxx,由此可知xxxx。而xxx的建筑风格与xxx并不相近,因为xxxx,所以xxx为最相似的地点 + +图片主特征: {maintraits} +文件内容:{filecontents} +""" + +prompt = PromptTemplate.from_template(template) + + +# 1.根据主特征和候选特征进行judge +def judge_byModel(maintraits, file_path): + # 自动检测文件编码 + with open(file_path, 'rb') as f: + raw_data = f.read() # 读取文件的二进制内容 + result = chardet.detect(raw_data) # 检测编码 + encoding = result['encoding'] # 获取检测到的编码 + + # 使用检测到的编码读取文件内容 + with open(file_path, 'r', encoding=encoding) as f: + filecontents = f.read() # 读取整个文件内容 + + chain_input = {"maintraits": maintraits, "filecontents": filecontents} + + chain = prompt | llm + judge_content = chain.invoke(chain_input) + return judge_content diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..938c0e0 Binary files /dev/null and b/requirements.txt differ diff --git a/service/ImageService.py b/service/ImageService.py new file mode 100644 index 0000000..5ae7e6a --- /dev/null +++ b/service/ImageService.py @@ -0,0 +1,33 @@ +from game.utils.process_image_traits import extract_traits_from_otherImages # 处理特征数据 +from game.model.modelVL import get_other_image_traits, get_image_traits # 得到图像的特征 + +""" +1.得到多图像的特征,并对数据进行处理得到主要部分 +""" + + +def getTraitsFrom_Images(image_paths): + traits = get_other_image_traits(image_paths) # 读取的是url + processed_traits = extract_traits_from_otherImages(traits) + return processed_traits + + +""" +2.返回主图像的特征 +""" + + +def getTraitsFrom_Image(image_path): + traits = get_image_traits(image_path) # 读取本地上传的图片 + processed_main_traits = extract_traits_from_otherImages(traits) + return processed_main_traits + + +if __name__ == "__main__": + image_paths = ['https://aos-comment.amap.com/B00155LGHO/headerImg/content_media_external_images_media_66314_1659242286949_d6a6a0e8.jpg', + 'https://aos-comment.amap.com/B00155LGHO/headerImg/0b7ebe391f0b82eff50fa6373861f7b3_2048_2048_80.jpg'] + image_path = "D://Answer//python-learning//Fuction//game//image//sues01.png" + other_images_traits = getTraitsFrom_Images(image_paths) + # main_image_traits = getTraitsFrom_Image(image_path) + print("\ncompare:", other_images_traits) + # print("\nmain:", main_image_traits) diff --git a/service/searchService.py b/service/searchService.py new file mode 100644 index 0000000..b01bbf0 --- /dev/null +++ b/service/searchService.py @@ -0,0 +1,72 @@ +from game.websearch.SearchFromBC import bocha_web_search # 博查搜索 +from game.utils.process_web_model import extract_places_byModel, \ + extract_lng_lat_byModel # 处理博查搜索的内容,利用大模型的总结能力得到松江大学城的建筑物 +from game.utils.process_web_data import extract_snippets, extract_urls # 对博查外部搜索的数据进行处理,得到url和content +from game.mapSearch.aroudplaces import amap_place_search # 搜索地标周围的地点 +from game.utils.process_map_data import extract_poi_names_and_photos # 对地标周围点的具体数据进行处理,以得到关键数据 +from game.utils.process_places_data import extract_songjiang_places # 通过正则过滤得到松江大学城地标建筑物集合 + +""" +1.通过外部搜索得到关于question的urls +""" + + +def getUrlsFromWeb(question): + temp_results = bocha_web_search(question) # 得到在外部网站上关于question的资料 + urls_from_web = extract_urls(temp_results) # 得到资料中的urls + print("\nUrlsFromWeb:", urls_from_web) + return urls_from_web + + +""" +2.通过外部搜索并给到大模型处理得到松江大学城里的建筑物 +- 然后通过正则函数得到松江大学城的建筑物集合 +""" + + +def getPlacesFromWeb(question): + temp_results = bocha_web_search(question) # 得到在外部网站上关于question的资料 + data_from_web = extract_snippets(temp_results) # 得到资料中的snippets + places = extract_places_byModel(data_from_web) # 根据snippets丢给大模型总结出提到的地址 + songjiang_places = extract_songjiang_places(places) + print("\nsongjiang_places:", songjiang_places) + return songjiang_places + + +""" +3.得到所有候选建筑物的特点 +""" + + +def getTraitsFromPlaces(question): + temp_results = bocha_web_search(question) # 得到在外部网站上关于question的资料 + data_from_web = extract_snippets(temp_results) # 得到资料中的data + print("\nTraitsOfPlace:", data_from_web) + return data_from_web + + +""" +4.返回地点的经纬度 +""" + + +def getLngAndLat_FromPlaces(question): + temp_results = bocha_web_search(question) # 得到在外部网站上关于question的资料 + data_from_web = extract_snippets(temp_results) # 得到资料中的data + lng_lat = extract_lng_lat_byModel(data_from_web) + return lng_lat + + +""" +5.返回松江大学城周围的地点和图片 +""" + + +def getAroud_smallplace_On_bigPlace(place_name): + place_name = place_name + "(松江)" + aroud_result = amap_place_search(place_name) + print(aroud_result) + small_names, small_name_photos = extract_poi_names_and_photos(aroud_result) # 返回中心点的周围地点名称和图像内容"" + print(f"{place_name}周围的地标:{small_names}") + print(f"{place_name}周围的地标的图像集合:{small_names}") + return small_names, small_name_photos diff --git a/tempfile/output_audio.mp3 b/tempfile/output_audio.mp3 new file mode 100644 index 0000000..f1bf27a Binary files /dev/null and b/tempfile/output_audio.mp3 differ diff --git a/tempfile/temp_image_traits b/tempfile/temp_image_traits new file mode 100644 index 0000000..18ef22f --- /dev/null +++ b/tempfile/temp_image_traits @@ -0,0 +1,11 @@ +'1. **建筑风格**: + - 这些建筑具有独特的几何形状,尤其是三角形和多边形的结构。 + - 建筑物的外观设计独特,可能是由玻璃和混凝土等材料构成。 + +2. **环境**: + - 周围有绿化带和树木。 + - 有水体和桥梁。 + +3. **地理位置**: + - 这些建筑位于一个较大的区域,周围有其他建筑物和设施。 + - 远处可以看到山脉。' \ No newline at end of file diff --git a/tempfile/temp_place_traits b/tempfile/temp_place_traits new file mode 100644 index 0000000..517a140 --- /dev/null +++ b/tempfile/temp_place_traits @@ -0,0 +1,2 @@ +1. **建筑风格**:\n - 这些建筑具有独特的几何形状,尤其是三角形和多边形的结构。\n - 建筑物的外观设计独特,可能是由玻璃和混凝土等材料构成。\n\n2. **环境**:\n - 周围有绿化带和树木。\n - 有水体和桥梁。\n\n3. **地理位置**:\n - 这些建筑位于一个较大的区域,周围有其他建筑物和设施。\n - 远处可以看到山脉。 + diff --git a/tempfile/temp_urls b/tempfile/temp_urls new file mode 100644 index 0000000..e69de29 diff --git a/tts/text_to_video.py b/tts/text_to_video.py new file mode 100644 index 0000000..d6c8d79 --- /dev/null +++ b/tts/text_to_video.py @@ -0,0 +1,52 @@ +import asyncio +import edge_tts +import os + + +async def text_to_speech(text: str, voice: str, output_file: str) -> None: + """将文本转换为语音并保存为音频文件。""" + communicate = edge_tts.Communicate(text, voice) + await communicate.save(output_file) + + +def generate_audio(text: str, voice: str = "zh-CN-YunyangNeural") -> str: + """ + 将文本转换为语音并保存为音频文件,输出到相邻的 tempfile 目录。 + + 参数: + - text: 要转换为语音的文本。 + - voice: 使用的语音模型(默认为 'zh-CN-YunyangNeural')。 + + 返回值: + - 生成的音频文件的路径。 + """ + # 1.获取当前代码所在目录 + current_dir = os.path.dirname(os.path.abspath(__file__)) # 获取当前脚本所在的绝对路径 + + # 2.指定音频文件保存到 tempfile 目录 + output_dir = os.path.join(current_dir, "..", "tempfile") # 生成 tempfile 目录的路径(与 tts 目录同级) + + # 3.确保输出目录存在 + if not os.path.exists(output_dir): + os.makedirs(output_dir) # 如果目录不存在,则创建目录 + + # 4.基于文本或生成随机文件名 + output_file = os.path.join(output_dir, "output_audio.mp3") # 保存的文件名为 output_audio.mp3 + + # 5.运行异步->文本到语音转换函数 + loop = asyncio.get_event_loop_policy().get_event_loop() # 获取事件循环 + try: + loop.run_until_complete(text_to_speech(text, voice, output_file)) # 运行异步任务,生成音频 + finally: + loop.close() # 关闭事件循环 + + return output_file # 返回生成的音频文件路径 + + +# 使用示例 +if __name__ == "__main__": + TEXT = "分析:上海工程技术大学松江校区图书馆的建筑风格与图片主特征最相近,特征为:具有独特的几何形状,主要以三角形和多边形为主,设计现代且具有未来感。由此可知,该地点的建筑风格与图片中的描述高度一致。而上海视觉艺术学院设计楼的建筑风格虽然现代化,但更侧重于简洁的线条和大面积的玻璃窗,并不完全符合图片中提到的独特几何形状的特点;上海工程技术大学松江校区体育馆则更多地采用了金属结构和呈现波浪形或弧形的屋顶设计,这些特征与图片中的描述也有一定差异。因此,上海工程技术大学松江校区图书馆为最相似的地点。" + + # 生成音频并获取输出文件路径 + audio_path = generate_audio(TEXT) # 调用生成音频函数 + print(f"音频文件保存路径: {audio_path}") # 打印生成的音频文件路径 diff --git a/utils/image_read.py b/utils/image_read.py new file mode 100644 index 0000000..80168d6 --- /dev/null +++ b/utils/image_read.py @@ -0,0 +1,17 @@ +import base64 +import requests + +# 1.读取图像 +def encode_image(file_path_or_url): + try: + if file_path_or_url.startswith('http'): + response = requests.get(file_path_or_url) + image_data = response.content + else: + with open(file_path_or_url, "rb") as image_file: + image_data = image_file.read() + return base64.b64encode(image_data).decode('ascii') + except Exception as e: + print(f"Error processing the image: {e}") + return None + diff --git a/utils/process_image_traits.py b/utils/process_image_traits.py new file mode 100644 index 0000000..e6053ca --- /dev/null +++ b/utils/process_image_traits.py @@ -0,0 +1,54 @@ +import json +import requests + +""" +1.提取特征中的主要内容content +""" + + +def extract_traits_from_otherImages(response_json): + # 将字符串转换为字典 + response_dict = json.loads(response_json) + + # 获取 content 的内容 + content = response_dict.get("choices", [])[0].get("message", {}).get("content", "") + + return content + + +""" +2.计算文本的向量 +""" + + +def get_trait_embedding(input_text): + url = "https://api.siliconflow.cn/v1/embeddings" + + payload = { + "model": "BAAI/bge-large-zh-v1.5", + "input": input_text, + "encoding_format": "float" + } + headers = { + "accept": "application/json", + "content-type": "application/json", + "authorization": "Bearer sk-kifqepgmrmlstabhxlmxrylkppvcppumtvwcdbwajgotuvvk" + } + + response = requests.post(url, json=payload, headers=headers) + + # 确认响应状态码是成功的 + if response.status_code == 200: + response_data = response.json() + # 提取embedding数据 + embeddings = response_data.get('data')[0].get('embedding') + return embeddings + else: + print("Error:", response.status_code, response.text) + return None + + +# 使用示例 +input_text = "硅基流动embedding上线,多快好省的 embedding 服务,快来试试吧" +embedding_result = get_trait_embedding(input_text) +print(embedding_result) diff --git a/utils/process_map_data.py b/utils/process_map_data.py new file mode 100644 index 0000000..180934e --- /dev/null +++ b/utils/process_map_data.py @@ -0,0 +1,80 @@ +def extract_poi_names_and_photos(response): + """ + 提取API响应中的POI名称和对应的照片信息,并收集所有POI的照片到一个大集合中。 + + 参数: + response (dict): 高德API返回的响应数据 + + 返回: + names_set (set): 所有POI名称的集合 + name_photos_dict (dict): 每个POI名称对应的照片集合 + all_photos_set (set): 所有POI的照片的大集合 + """ + pois = response.get('pois', []) # 获取POI列表,默认为空列表 + + names_set = set() # 存储所有POI名称的集合 + name_photos_dict = {} # 存储每个POI名称对应的照片集合 + all_photos_set = set() # 存储所有POI的照片(大集合) + + for poi in pois: + # 提取名称 + name = poi.get('name') + if name: + names_set.add(name) # 将名称添加到集合中 + + # 提取photos + photos = poi.get('photos', []) + photo_urls = {photo.get('url') for photo in photos if 'url' in photo} # 提取所有照片的URL + + # 更新 name_photos_dict + if name in name_photos_dict: + name_photos_dict[name].update(photo_urls) # 如果name已经存在,更新它的照片集合 + else: + name_photos_dict[name] = photo_urls # 否则,创建新的照片集合 + + # 将这些照片URL加入总的照片集合中 + all_photos_set.update(photo_urls) + + return names_set, name_photos_dict + + +# # 示例API响应 +# response = { +# "pois": [ +# { +# "name": "上海工程技术大学松江校区", +# "photos": [ +# {"url": "http://photo1.com/photo1.jpg"}, +# {"url": "http://photo2.com/photo2.jpg"} +# ] +# }, +# { +# "name": "北京大学", +# "photos": [ +# {"url": "http://photo3.com/photo3.jpg"} +# ] +# }, +# { +# "name": "复旦大学", +# "photos": [] # 没有照片的POI +# }, +# { +# "name": "上海工程技术大学松江校区", # 同一个名称,更多照片 +# "photos": [ +# {"url": "http://photo4.com/photo4.jpg"} +# ] +# } +# ] +# } +# +# # 提取POI名称和照片 +# names, name_photos = extract_poi_names_and_photos(response) +# +# # 打印结果 +# print("POI名称集合:", names) +# print("POI名称与对应照片集合:") +# for name, photos in name_photos.items(): +# print(f"{name}: {photos}") +# +# print("\n所有POI的照片集合:") +# print(name_photos) diff --git a/utils/process_places_data.py b/utils/process_places_data.py new file mode 100644 index 0000000..45cf124 --- /dev/null +++ b/utils/process_places_data.py @@ -0,0 +1,24 @@ +import re + + +def extract_songjiang_places(text): + # 定义正则表达式来匹配序号后面的内容,直到遇到空格为止 + pattern = r'\d+\.\s*([^\s]+)' # 匹配格式如 '1. 内容' + + # 使用 re.findall 提取所有符合条件的内容 + content = re.findall(pattern, text) + + # 返回一个包含唯一内容的集合 + return set(content) + + +# 示例文本 +text = '''1. 上海工程技术大学松江校区 +2. 东华大学 +3. 华东政法大学 + +根据所提供的数据,仅明确提到了上海工程技术大学松江校区位于松江大学城内,但依据松江大学城普遍认知,东华大学和华东政法大学也位于松江大学城内。其他具体建筑物或校区未在数据中被明确提及。''' + +# 调用函数并输出结果 +content_after_number = extract_songjiang_places(text) +print(content_after_number) diff --git a/utils/process_set_tolist.py b/utils/process_set_tolist.py new file mode 100644 index 0000000..57632cb --- /dev/null +++ b/utils/process_set_tolist.py @@ -0,0 +1,14 @@ +""" +1.将set集合数据转为list集合数据 +""" + + +def convert_sets_to_lists(obj): + if isinstance(obj, set): + return list(obj) + elif isinstance(obj, list): + return [convert_sets_to_lists(item) for item in obj] + elif isinstance(obj, dict): + return {key: convert_sets_to_lists(value) for key, value in obj.items()} + else: + return obj diff --git a/utils/process_web_data.py b/utils/process_web_data.py new file mode 100644 index 0000000..6fbf81c --- /dev/null +++ b/utils/process_web_data.py @@ -0,0 +1,67 @@ +import json + +def extract_snippets(data): + snippets = [] + idx = 1 + for message in data.get('messages', []): + if message['type'] == 'source' and message['content_type'] in ('webpage', 'text', 'douyin'): + try: + content = json.loads(message.get('content', '{}')) + if 'value' in content: + for item in content['value']: + snippet = item.get('snippet') + if snippet: + snippets.append(f"{idx}. {snippet}") + idx += 1 + if 'videos' in content: + for video in content['videos']: + snippet = video.get('description') + if snippet: + snippets.append(f"{idx}. {snippet}") + idx += 1 + except json.JSONDecodeError: + continue + return snippets + +def extract_urls(data): + urls = [] + idx = 1 + for message in data.get('messages', []): + if message['type'] == 'source' and message['content_type'] in ('webpage', 'text', 'douyin'): + try: + content = json.loads(message.get('content', '{}')) + if 'value' in content: + for item in content['value']: + if 'url' in item and item['url'] not in urls: + urls.append(f"{idx}. {item['url']}") + idx += 1 + if len(urls) == 6: + return urls + if 'contentUrl' in item and item['contentUrl'] not in urls: + urls.append(f"{idx}. {item['contentUrl']}") + idx += 1 + if len(urls) == 6: + return urls + if 'thumbnailUrl' in item and item['thumbnailUrl'] not in urls: + urls.append(f"{idx}. {item['thumbnailUrl']}") + idx += 1 + if len(urls) == 6: + return urls + if 'videos' in content: + for video in content['videos']: + content_url = video.get('content_url') + if content_url and content_url not in urls: + urls.append(f"{idx}. {content_url}") + idx += 1 + if len(urls) == 6: + return urls + for image in video.get('cover_images', []): + image_url = image.get('url') + if image_url and image_url not in urls: + urls.append(f"{idx}. {image_url}") + idx += 1 + if len(urls) == 6: + return urls + except json.JSONDecodeError: + continue + return urls diff --git a/utils/process_web_model.py b/utils/process_web_model.py new file mode 100644 index 0000000..5882fdc --- /dev/null +++ b/utils/process_web_model.py @@ -0,0 +1,50 @@ +import os +from langchain_community.llms import Tongyi +from langchain_core.prompts import PromptTemplate + +# 1. 设置API密钥 +os.environ["SERPAPI_API_KEY"] = "31a3c96f0ce535fd1b43117d3c9298c66753b6dae1da9074708f03ecc8282367" +os.environ["DASHSCOPE_API_KEY"] = "sk-d07d9d5c4d8d4158abbaf45a40c10042" + +# 2. 导入所需的库和模型 +DASHSCOPE_API_KEY = "sk-d07d9d5c4d8d4158abbaf45a40c10042" +llm = Tongyi(dashscope_api_key="sk-d07d9d5c4d8d4158abbaf45a40c10042", model="qwen-plus") + +# 3. 设置template +template = """你现在扮演的是一名专业的信息提取工程师。请根据以下数据中提取并列举出松江大学城内的所有建筑物。请确保结果清晰且按编号列出。 + +要求: +1. 只列出建筑物的名称,无需加其他任何内容。 +2. 每个建筑物一行,用数字序号标记。 +3. 结果格式示例: + 1. 上海工程技术大学 + 2. 东华大学 + 3. 华东政法大学 + +数据如下: {question} +""" +template2 = """你现在扮演的是一名专业的信息提取工程师。请根据以下数据中提取出经纬度,并只需要返回经纬度即可。 + +要求: +1. 只列出经纬度,无需加其他任何内容。 +2. 经度在前,纬度在后 +3. 结果格式示例: + 121.205007,31.056050 + +数据如下: {question} +""" + +prompt = PromptTemplate.from_template(template) +prompt2 = PromptTemplate.from_template(template2) + +# 1.处理网络搜索后的数据,返回指定格式的建筑物 +def extract_places_byModel(question): + chain = prompt | llm + places = chain.invoke({"question": question}) + return places + +# 2.返回地理位置的经纬度 +def extract_lng_lat_byModel(question): + chain = prompt2 | llm + lng_lat = chain.invoke({"question": question}) + return lng_lat \ No newline at end of file diff --git a/utils/searchFromSera.py b/utils/searchFromSera.py new file mode 100644 index 0000000..336f692 --- /dev/null +++ b/utils/searchFromSera.py @@ -0,0 +1,8 @@ +from langchain.utilities import SerpAPIWrapper +import os + + +os.environ["SERPAPI_API_KEY"] = '31a3c96f0ce535fd1b43117d3c9298c66753b6dae1da9074708f03ecc8282367' +search = SerpAPIWrapper() +result = search.run("松江大学城中的上海工程技术大学的所有建筑物?") +print(result) diff --git a/utils/similarity_read.py b/utils/similarity_read.py new file mode 100644 index 0000000..a26bfd4 --- /dev/null +++ b/utils/similarity_read.py @@ -0,0 +1,41 @@ +import tempfile +import json +import os + +""" +1.将相似度最高的信息存储到一个文件当中 +""" + + +def write_top_similarities_to_file(top_3_similarities, save_path): + """ + 将前三个相似度最高的地标信息及其特征写入指定路径的临时文件中。 + + 参数: + - top_3_similarities: 包含地标、相似度和特征的前三个相似度信息列表 + - save_path: 保存临时文件的路径 + + 返回: + - temp_file_name: 临时文件的完整路径 + """ + # 确保保存路径存在 + if not os.path.exists(save_path): + os.makedirs(save_path) + + # 将前三个相似度最高的地标信息及其特征写入临时文件 + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt', encoding='utf-8', + dir=save_path) as temp_file: + for small_name, similarity, big_place, traits in top_3_similarities: + # 写入 small_place, similarity, 和 traits 信息 + temp_file.write(f"Small Place: {small_name}\n") + temp_file.write(f"Similarity: {similarity}\n") + temp_file.write(f"Traits: {json.dumps(traits, ensure_ascii=False, indent=4)}\n") + + # 写入分隔线 + divider = '---------------------------' + temp_file.write(f"{divider}\n") + + # 保存临时文件的路径 + temp_file_name = temp_file.name + print(f"前三个相似度最高的小地标信息已写入临时文件:{temp_file_name}") + return temp_file_name diff --git a/websearch/SearchFromBC.py b/websearch/SearchFromBC.py new file mode 100644 index 0000000..7ecd941 --- /dev/null +++ b/websearch/SearchFromBC.py @@ -0,0 +1,54 @@ +import requests +from game.utils.process_web_data import extract_urls, extract_snippets +from game.utils.process_web_model import extract_places_byModel + +# 直接在代码中填入 API 密钥ai +BOCHA_API_KEY = 'sk-41d21b258d5c4e68a08d9821745bee21' + + +# 1.定义博查 Web 搜索的工具函数 +def bocha_web_search(query, count=8): + url = 'https://api.bochaai.com/v1/ai-search' # 确保 API 端点正确 + headers = { + 'Authorization': f'Bearer {BOCHA_API_KEY}', # 使用直接填入的博查 API 密钥 + 'Content-Type': 'application/json' + } + # 设置请求体,查询和返回条数 + data = { + 'query': query, + 'count': count + } + + # 发送 POST 请求 + response = requests.post(url, headers=headers, json=data) + + # 检查是否成功 + if response.status_code == 200: + return response.json() # 返回解析后的 JSON 响应 + else: + print(f"请求失败,状态码: {response.status_code}") + return {} + + +# 示例用法 +if __name__ == "__main__": + query = "松江大学城上海工程技术大学的经纬度坐标在哪?" + # query = "上海工程技术大学有哪些建筑物?" + result = bocha_web_search(query) + print(result) + # 提取所有的 snippet + snippets = extract_snippets(result) + print("Snippets:") + for snippet in snippets: + print(snippet) + + # 提取前 5 个 url + urls = extract_urls(result) + print("\nURLs:") + for url in urls: + print(url) + + # 对web外部搜索的相关信息进行处理返回范围更加小的信息(比如:松江大学城附近的建筑物) + places = extract_places_byModel(snippets) + + print(places)