Commit d9c9e149 authored by Yaowentong's avatar Yaowentong

fix

parent 9e2baa4f
...@@ -136,6 +136,35 @@ class BaseConfig: ...@@ -136,6 +136,35 @@ class BaseConfig:
} }
} }
def get_sec_id(user_id):
import requests
url = f"https://api.douchacha.com/open/d/hx/user/user_info?user_id={user_id}"
payload = {}
headers = {
'Authorization': 'eyJhbGciOiJIUzI1NiJ9.eyJ0eXBlIjoiUEMiLCJ1c2VySWQiOjEzOTE2OTMxOTU3NTQyMjU2NjQsImNyZWF0ZURhdGUiOiIyMDI2LTA2LTAzIDE3OjE4OjEzIiwiZXhwIjoxNzgzMDcwMjkzfQ.S12OckXnT7PZot-dnQHPFoFmL3GTZ8M1IDL6x2aWeKU'
}
response = requests.request("GET", url, headers=headers, data=payload)
return response.json().get('data').get('sec_uid')
def get_user_info(secUid):
import requests
url = f"http://172.16.1.37:8873/collect_user_info?secUid={secUid}"
payload = {}
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
if __name__ == '__main__': if __name__ == '__main__':
key_list = ['BDAI:geo:stream_batch:list', key_list = ['BDAI:geo:stream_batch:list',
'BDAI:geo:batch:list', 'BDAI:geo:batch:list',
...@@ -163,11 +192,25 @@ if __name__ == '__main__': ...@@ -163,11 +192,25 @@ if __name__ == '__main__':
'WXYY:geo:batch:list', 'WXYY:geo:batch:list',
'geo:task_commit:list'] 'geo:task_commit:list']
t = init_redis() t = init_redis()
# # print(t.scard('mt_third_task'))
# aa = list(aa)
# for a in aa:
# sec_uid = get_sec_id(a)
# get_user_info(sec_uid)
# print(t.scard('third_hx_user_id'))
while 1: while 1:
for k in key_list: for k in key_list:
print(f"{k}----{t.llen(k)}") print(f"{k}----{t.llen(k)}")
time.sleep(10) time.sleep(10)
# key = "third_cx_user_id"
# #
# print(len(t.smembers(key))) # print(len(t.smembers(key)))
# -*- coding: utf-8 -*-
import os import os
import time import time
...@@ -184,9 +185,6 @@ def export_all_brand_excel(data_list, phone, begin): ...@@ -184,9 +185,6 @@ def export_all_brand_excel(data_list, phone, begin):
def get_req_id(phone, begin, end): def get_req_id(phone, begin, end):
print(phone)
print(begin)
print(end)
url = f"https://openapi.aidso.com/openapi/ywt/geoReqList?phone={phone}&begin={begin} 00:00:00&end={end} 23:59:59" url = f"https://openapi.aidso.com/openapi/ywt/geoReqList?phone={phone}&begin={begin} 00:00:00&end={end} 23:59:59"
payload = {} payload = {}
...@@ -241,6 +239,41 @@ def generate_date_list(start_date: str, end_date: str): ...@@ -241,6 +239,41 @@ def generate_date_list(start_date: str, end_date: str):
return result return result
def get_refer_rate_heatmap(brand_library_id, user_id, begin_time, end_time):
url = "https://openapi.aidso.com/openapi/ywt/platforms"
payload = json.dumps({
"brand_library_id": brand_library_id,
"user_id": user_id,
"begin_time": f"{begin_time} 00:00:00",
"end_time": f"{end_time} 23:59:59"
})
headers = {
'Content-Type': 'application/json'
}
try:
response = requests.post(
url,
headers=headers,
data=payload,
timeout=15
)
response.raise_for_status()
result = response.json()
if result.get("code") == 200:
return result.get("data", {})
return []
except requests.RequestException as e:
print(f"请求失败: {e}")
return []
except ValueError as e:
print(f"返回结果不是合法 JSON: {e}")
return []
# print(response.text)
def get_platforms(brand_library_id, user_id, begin_time, end_time): def get_platforms(brand_library_id, user_id, begin_time, end_time):
url = "https://openapi.aidso.com/openapi/ywt/platforms" url = "https://openapi.aidso.com/openapi/ywt/platforms"
...@@ -640,7 +673,12 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -640,7 +673,12 @@ def zhou_report(phone, begin, end, brand_name):
result = [] result = []
platform_data = get_platforms(brand_id, user_id, begin, end) platform_data = get_platforms(brand_id, user_id, begin, end)
refer_rate_heatmap = get_refer_rate_heatmap(brand_id, user_id, begin, end)
print('---')
print('---')
print(refer_rate_heatmap)
print('---')
print('---')
geo_refer_rank_overview_vos = platform_data.get('geo_refer_rank_overview_vos') geo_refer_rank_overview_vos = platform_data.get('geo_refer_rank_overview_vos')
brand_overview = platform_data.get('brand_overview') brand_overview = platform_data.get('brand_overview')
for item in geo_refer_rank_overview_vos: for item in geo_refer_rank_overview_vos:
...@@ -669,9 +707,7 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -669,9 +707,7 @@ def zhou_report(phone, begin, end, brand_name):
'品牌得分': brand_overview.get('brand_score') '品牌得分': brand_overview.get('brand_score')
}) })
# 概览数据 # 概览数据
print(f"概览数据:{brand_overview_result}")
# 分平台数据 # 分平台数据
print(f"分平台数据:{result}")
all_word = get_all_word_rank(brand_id, user_id, begin, end) all_word = get_all_word_rank(brand_id, user_id, begin, end)
all_word_result = [] all_word_result = []
...@@ -684,7 +720,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -684,7 +720,6 @@ def zhou_report(phone, begin, end, brand_name):
"平均提及排名": all.get("avg_rank") "平均提及排名": all.get("avg_rank")
}) })
# 全部品牌词数据 # 全部品牌词数据
print(f"全部品牌词数据{all_word_result}")
overview_result = [] overview_result = []
sentiment_overview = get_sentiment_overview(brand_id, user_id, begin, end) sentiment_overview = get_sentiment_overview(brand_id, user_id, begin, end)
...@@ -702,7 +737,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -702,7 +737,6 @@ def zhou_report(phone, begin, end, brand_name):
"负面引用文章": sentiment_overview.get('negative_count') "负面引用文章": sentiment_overview.get('negative_count')
} }
) )
print(f"overview_result{overview_result}")
platform_sentiment_result = [] platform_sentiment_result = []
platform_sentiment = get_platforms_sentiment(brand_id, user_id, begin, end) platform_sentiment = get_platforms_sentiment(brand_id, user_id, begin, end)
for pla in platform_sentiment: for pla in platform_sentiment:
...@@ -714,7 +748,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -714,7 +748,6 @@ def zhou_report(phone, begin, end, brand_name):
"提及品牌次数": pla.get('brand_words_count'), "提及品牌次数": pla.get('brand_words_count'),
"引用来源": pla.get('source_count'), "引用来源": pla.get('source_count'),
}) })
print(platform_sentiment_result)
platform_list = ["DB", "DP", "TYQW", "TXYB", "BDAI", "DOUBA", "DPA", "DYAI", "KIMI", "WXYY"] platform_list = ["DB", "DP", "TYQW", "TXYB", "BDAI", "DOUBA", "DPA", "DYAI", "KIMI", "WXYY"]
url_top_40 = get_url_top40(user_id, brand_id, begin, end, platform_list) url_top_40 = get_url_top40(user_id, brand_id, begin, end, platform_list)
...@@ -725,7 +758,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -725,7 +758,6 @@ def zhou_report(phone, begin, end, brand_name):
"引用次数": url.get('log_count'), "引用次数": url.get('log_count'),
"引用占比": url.get('quote_ratio_percent'), "引用占比": url.get('quote_ratio_percent'),
}) })
print(url_top_40_result)
site_category = get_site_category(brand_id, user_id, begin, end, platform_list) site_category = get_site_category(brand_id, user_id, begin, end, platform_list)
site_category_result = [] site_category_result = []
...@@ -737,7 +769,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -737,7 +769,6 @@ def zhou_report(phone, begin, end, brand_name):
"引用次数": site.get('total_log_count'), "引用次数": site.get('total_log_count'),
"引用率": site.get('quote_rate'), "引用率": site.get('quote_rate'),
}) })
print(site_category_result)
quote_mention_word_cloud = get_quote_mention_word_cloud(brand_id, user_id, begin, end) quote_mention_word_cloud = get_quote_mention_word_cloud(brand_id, user_id, begin, end)
positive_top = quote_mention_word_cloud.get('positive_top') positive_top = quote_mention_word_cloud.get('positive_top')
...@@ -755,8 +786,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -755,8 +786,6 @@ def zhou_report(phone, begin, end, brand_name):
"关键词": negative.get('word'), "关键词": negative.get('word'),
"出现次数": negative.get('count'), "出现次数": negative.get('count'),
}) })
print(positive_top_result)
print(negative_top_result)
quto_statistics_result = [] quto_statistics_result = []
quto_statistics = get_quto_statistics(brand_id, user_id, begin, end) quto_statistics = get_quto_statistics(brand_id, user_id, begin, end)
quto_statistics_result.append({ quto_statistics_result.append({
...@@ -764,7 +793,6 @@ def zhou_report(phone, begin, end, brand_name): ...@@ -764,7 +793,6 @@ def zhou_report(phone, begin, end, brand_name):
"引用次数": quto_statistics.get('total_log_count'), "引用次数": quto_statistics.get('total_log_count'),
"引用网站": quto_statistics.get('site_count'), "引用网站": quto_statistics.get('site_count'),
}) })
print(quto_statistics_result)
return { return {
"brand_overview_result":brand_overview_result, "brand_overview_result":brand_overview_result,
"result":result, "result":result,
...@@ -933,7 +961,43 @@ def dao_report(phone, begin, end, brand_name,platform=None): ...@@ -933,7 +961,43 @@ def dao_report(phone, begin, end, brand_name,platform=None):
for item in result: for item in result:
f.write(json.dumps(item, ensure_ascii=False) + "\n\n\n") f.write(json.dumps(item, ensure_ascii=False) + "\n\n\n")
def get_platforms_q(brand_library_id, user_id, begin_time, end_time,question_list):
url = "https://openapi.aidso.com/openapi/ywt/platforms"
payload = json.dumps({
"brand_library_id": brand_library_id,
"user_id": user_id,
"begin_time": f"{begin_time} 00:00:00",
"end_time": f"{end_time} 23:59:59",
"question_list":question_list
})
print(question_list)
headers = {
'Content-Type': 'application/json'
}
try:
response = requests.post(
url,
headers=headers,
data=payload,
timeout=15
)
response.raise_for_status()
result = response.json()
if result.get("code") == 200:
return result.get("data", {})
return []
except requests.RequestException as e:
print(f"请求失败: {e}")
return []
except ValueError as e:
print(f"返回结果不是合法 JSON: {e}")
return []
# print(response.text)
# ========================= # =========================
# 使用示例 # 使用示例
# ========================= # =========================
...@@ -948,16 +1012,28 @@ if __name__ == "__main__": ...@@ -948,16 +1012,28 @@ if __name__ == "__main__":
# AIDSO爱搜 这个品牌 # AIDSO爱搜 这个品牌
# 最近7天 # 最近7天
# 所有问题 # 所有问题
phone = 15652410076 # phone = 15100000036
begin = '2026-05-11' # begin = '2026-06-08'
end = '2026-06-02' # end = '2026-06-08'
brand_name = ['葆蝶家-第一批','葆蝶家-第二批','BV葆蝶家','葆蝶家'] # print(get_req_id(phone,begin,end))
for b in brand_name: # brand_name = ['葆蝶家-第一批','葆蝶家-第二批','BV葆蝶家','葆蝶家']
zhou_report(phone, begin, end, b) # for b in brand_name:
qian_report(phone,begin,end,b) # zhou_report(phone, begin, end, b)
# # qian_report(phone,begin,end,b)
# qian_report(phone,begin,end,b) # qian_report(phone,begin,end,b)
brand_library_id = 2063180776253702144
user_id = 2063177785609949184
begin = '2026-06-08'
end = '2026-06-08'
qu_list = ['东鹏瓷砖怎么样','东鹏瓷砖质量好不好','东鹏瓷砖值得买吗','东鹏瓷砖是几线品牌','东鹏瓷砖和马可波罗哪个好','东鹏和冠珠瓷砖哪个好','东鹏和蒙娜丽莎哪个好','东鹏控股是做什么的','东鹏控股和东鹏饮料什么关系','瓷砖十大品牌有哪些','2026年瓷砖品牌排行榜前十名','中国瓷砖品牌排名前十','瓷砖一线品牌排名','国内瓷砖品牌排行榜','高端瓷砖品牌排行榜','高端瓷砖有哪些品牌','瓷砖头部品牌有哪些','大平层用什么瓷砖品牌','设计师推荐的高端瓷砖品牌','5A瓷砖品牌推荐哪个好','5A瓷砖品牌排行','5A国标瓷砖什么品牌好','5A瓷砖是什么标准','5A认证瓷砖推荐','品质好的瓷砖品牌有哪些','什么品牌的瓷砖品质最好','选好瓷砖认准什么品牌','瓷砖哪个牌子好','瓷砖品牌推荐','装修选什么瓷砖品牌好','瓷砖什么牌子质量好','2026年瓷砖品牌排行榜','瓷砖怎么选不踩坑','买瓷砖主要看哪几个指标','好瓷砖的标准是什么','瓷砖选购避坑指南','金丝绒瓷砖哪个牌子好','金丝绒瓷砖值得买吗','金丝绒瓷砖怎么样','木纹砖哪个牌子好','木纹砖推荐哪个品牌','木纹砖怎么选品牌','木纹砖和木地板哪个好','木纹砖品牌排行','莱姆石瓷砖哪个牌子好','莱姆石瓷砖品牌推荐','莱姆石瓷砖怎么选','什么品牌的莱姆石瓷砖好','客厅瓷砖什么牌子好','客厅铺什么瓷砖好看又耐用','客厅瓷砖怎么选品牌','客厅瓷砖品牌推荐','客厅用什么瓷砖显高级','厨房瓷砖什么牌子好','厨房用什么瓷砖好打理','厨房防油污瓷砖推荐哪个牌子','厨房瓷砖品牌推荐2026','厨房抗菌瓷砖推荐哪个品牌','卫生间瓷砖什么牌子好','卫生间瓷砖推荐哪个品牌','浴室防滑瓷砖哪个品牌好','卫生间防滑抗菌瓷砖推荐品牌','浴室抗菌瓷砖什么品牌好','全屋通铺瓷砖什么品牌好','全屋通铺瓷砖推荐哪个牌子','全屋瓷砖用什么品牌好','家里全屋铺瓷砖选什么牌子','全屋通铺瓷砖品牌排行','防滑瓷砖哪个牌子好','防滑瓷砖品牌推荐','好打理的瓷砖推荐哪个品牌','防污瓷砖什么品牌好','耐脏好清洁的瓷砖品牌推荐','耐磨瓷砖什么品牌好','不容易刮花的瓷砖推荐什么品牌','中古风装修用什么瓷砖品牌好','法式风格瓷砖推荐什么品牌','奶油风瓷砖什么品牌好','现代简约风格瓷砖推荐什么品牌','新中式瓷砖用什么品牌好','原木风瓷砖推荐哪个品牌','高级感装修瓷砖用什么品牌','岩板什么品牌好','岩板品牌推荐','750x1500地砖什么品牌好','岩板品牌排行','柔光砖什么品牌好','哑光瓷砖推荐哪个品牌','哑光砖品牌排名','哑光瓷砖什么品牌好','柔光砖品牌排行','哑光砖推荐哪个品牌耐脏','国家级建筑用的瓷砖是什么牌子','大型工程项目用什么瓷砖品牌','瓷砖行业有哪些上市公司','A股瓷砖上市公司有哪些','绿色建材瓷砖品牌有哪些','获得国家级绿色工厂认证的瓷砖企业有哪些','建材行业ESG表现好的企业有哪些','双碳目标下有哪些绿色建材瓷砖品牌']
result = []
for q in qu_list:
result.append((q,get_platforms_q(brand_library_id,user_id,begin,end,[q]).get('geo_refer_rank_overview_vos')))
# brand_name = 'AIDSO爱搜' # brand_name = 'AIDSO爱搜'
all_file = f"/Users/yaowentong/Desktop/dongpeng.txt"
with open(all_file, "w", encoding="utf-8") as f:
for item in result:
f.write(json.dumps(item, ensure_ascii=False) + "\n\n\n")
# platform = ['DB'] # platform = ['DB']
# dao_report(phone, begin, end, brand_name, platform) # dao_report(phone, begin, end, brand_name, platform)
# qian_report(start, end, keyword_list, file_name) # qian_report(start, end, keyword_list, file_name)
\ No newline at end of file
...@@ -141,6 +141,8 @@ def send_message(message): ...@@ -141,6 +141,8 @@ def send_message(message):
def get_task(): def get_task():
all_items = [] all_items = []
page_token = None page_token = None
...@@ -818,7 +820,7 @@ def runner_thread(): ...@@ -818,7 +820,7 @@ def runner_thread():
for cn in (0, 1, 2): for cn in (0, 1, 2):
try: try:
rows = bh_utils.query_data( rows = bh_utils.query_data(
f"select reqId,prompt,rank from geo_third_task_log where cn = {cn} and pt = {pt_today}" f"select reqId,prompt,rank,pt from geo_third_task_log where cn = {cn} and pt = {pt_today}"
) or [] ) or []
for row in rows: for row in rows:
row["thinking_enabled"] = "1" row["thinking_enabled"] = "1"
...@@ -1076,8 +1078,8 @@ def webhook_snipaste(promp_list): ...@@ -1076,8 +1078,8 @@ def webhook_snipaste(promp_list):
if __name__ == "__main__": if __name__ == "__main__":
# t1 = threading.Thread(target=scheduler_thread, daemon=True) t1 = threading.Thread(target=scheduler_thread, daemon=True)
# t2 = threading.Thread(target=runner_thread, daemon=True) t2 = threading.Thread(target=runner_thread, daemon=True)
# t1.start() # t1.start()
# t2.start() # t2.start()
# t1.join() # t1.join()
......
# -*- coding: utf-8 -*- import tldextract as tldextract
import time from openpyxl import load_workbook
import redis from aidso_geo.core.down_load_bot import get_req_id, plat_form_map
import requests from aidso_geo.utils import bh_utils, tos_utils
import json
from aidso_geo.core.commit_process import redis_client8
from aidso_geo.models import spider_save_tos
from aidso_geo.utils import tos_utils, bh_utils
from aidso_geo.config.base_config import init_redis
redis_client = init_redis()
def commit_task(platform):
url = "http://172.200.5.67:8086/api/geo/task_commit"
payload = json.dumps({
"prompt": "羽绒服品牌推荐",
"brandWords": [
"抖查查",
"哎搜"
],
"comWords": [
"蝉妈妈",
"考古加"
],
"taskId": "all_test_task1",
"reqId": f"all_test_req1{platform}",
"platform": platform,
"type": "stream"
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
return response.json().get('reqId')
def get_result(req):
url = f"http://172.200.5.67:8086/api/geo/task_check?reqId={req}"
payload = {}
headers = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.json())
import openpyxl
from openpyxl import Workbook from openpyxl import Workbook
import os from openpyxl.styles import Font, Alignment
import json
class ExcelWriter: def write_list_dict_to_excel(data_list, output_path):
""" """
Excel写入工具类,专门用于写入taskID和response两列数据 把 List[Dict] 写入 Excel
:param data_list: 例如 [{'prompt': 'xxx', 'platform_code': 'BDAI'}]
:param output_path: 输出 Excel 路径,例如 /Users/xxx/Desktop/result.xlsx
""" """
def __init__(self, file_path): if not data_list:
""" raise ValueError("data_list 不能为空")
初始化Excel写入工具
:param file_path: Excel文件保存路径(如: './output.xlsx')
"""
self.file_path = file_path
self.workbook = None
self.worksheet = None
# 初始化工作簿和工作表
self._init_workbook()
def _init_workbook(self):
"""初始化工作簿和工作表,若文件已存在则打开,不存在则新建"""
# 检查文件是否存在
if os.path.exists(self.file_path):
self.workbook = openpyxl.load_workbook(self.file_path)
# 取第一个工作表
self.worksheet = self.workbook.active
# 检查表头是否存在,不存在则添加
if self.worksheet.cell(row=1, column=1).value != 'taskID' or \
self.worksheet.cell(row=1, column=2).value != 'response':
# 在第一行插入表头
self.worksheet.insert_rows(1)
self.worksheet.cell(row=1, column=1, value='taskID')
self.worksheet.cell(row=1, column=2, value='response')
else:
# 新建工作簿
self.workbook = Workbook()
self.worksheet = self.workbook.active
# 设置表头
self.worksheet.cell(row=1, column=1, value='prompt')
self.worksheet.cell(row=1, column=2, value='platform')
self.worksheet.cell(row=1, column=3, value='context')
self.worksheet.cell(row=1, column=4, value='quote')
self.worksheet.cell(row=1, column=5, value='think')
self.worksheet.cell(row=1, column=6, value='time')
def write_batch_rows(self, data_list):
if not isinstance(data_list, list) or len(data_list) == 0:
raise ValueError("data_list必须是非空的列表")
# "taskId": i.get("taskId"),
# "prompt": i.get("prompt"),
# "platform": i.get("platform"),
# "insertime": i.get("insertime"),
# 找到下一个空行
next_row = self.worksheet.max_row + 1
# 批量写入数据
for idx, (prompt, platform, context, quote,think,time) in enumerate(data_list):
self.worksheet.cell(row=next_row + idx, column=1, value=prompt)
self.worksheet.cell(row=next_row + idx, column=2, value=platform)
self.worksheet.cell(row=next_row + idx, column=3, value=context)
self.worksheet.cell(row=next_row + idx, column=4, value=quote)
self.worksheet.cell(row=next_row + idx, column=5, value=think)
self.worksheet.cell(row=next_row + idx, column=6, value=time)
# 保存文件
self.workbook.save(self.file_path)
def close(self):
"""关闭工作簿,释放资源"""
if self.workbook:
self.workbook.close()
import time
from datetime import datetime
def timestamp_to_datetime(timestamp, fmt="%Y-%m-%d %H:%M:%S"):
timestamp = int(timestamp)
# 方法1:用datetime模块(推荐,更直观)
local_time = datetime.fromtimestamp(timestamp)
# 格式化时间
return local_time.strftime(fmt)
def process_batch():
query_list = bh_utils.query_data("""
select reqId,
prompt,
brandWords,
comWords,
taskId,
platform,
type,
thinkingEnabled as thinking_enabled,
searchEnabled as search_enabled,
comWordsMap
from geo_commit_task
where status = 'ING'
and type = 'stream_batch'
""")
print(len(query_list))
for i in query_list:
if i.get('comWordsMap'):
i['comWordsMap'] = json.loads(i.get('comWordsMap'))
if i.get('brandWords'):
i['brandWords'] = json.loads(i.get('brandWords'))
if i.get('comWords'):
i['comWords'] = json.loads(i.get('comWords'))
redis_client.lpush(f"{i['platform']}:geo:{i['type']}:list", json.dumps(i))
# redis_client.lpush(f"{i['platform']}:geo:stream_batch:list", json.dumps(i))
def to_excel(file_name):
query_list = bh_utils.query_data(
f"select * from geo_commit_task where prompt = '经济纠纷哪个律师比较厉害' and platform in ('DPA','DB','DOUBA','DP') ")
task_list = []
for i in query_list:
task_list.append(
{
"taskId": i.get("taskId"),
"prompt": i.get("prompt"),
"platform": i.get("platform"),
"insertime": i.get("insertime"),
}
)
plat_form_map = {
"DP": "deepseek网页版",
"DB": "豆包网页版",
"TXYB": "腾讯元宝",
"TYQW": "通义千问",
"KIMI": "kimi",
"WXYY": "文心一言",
"BDAI": "百度ai",
"DYAI": "抖音ai",
"DOUBA": "豆包安卓版",
"DPA": "deepseek安卓版",
}
batch_data = [] # 创建工作簿
for i in task_list: wb = Workbook()
taskId = i.get("taskId") ws = wb.active
prompt = i.get("prompt") ws.title = "result"
platform = i.get("platform")
time = i.get("insertime")
context_path = f'geo/{taskId}/{platform}/context.txt'
quote_path = f'geo/{taskId}/{platform}/quote.txt'
think = f'geo/{taskId}/{platform}/think.txt'
if tos_utils.check_file_in_tos(context_path):
batch_data.append(
(
prompt,
plat_form_map.get(platform),
tos_utils.get_string_from_tos(context_path),
tos_utils.get_string_from_tos(quote_path),
tos_utils.get_string_from_tos(think),
timestamp_to_datetime(time)
)
)
excel_writer = ExcelWriter(f"/Users/yaowentong/Desktop/{file_name}.xlsx") # 取第一条数据的 key 作为表头
headers = list(data_list[0].keys())
excel_writer.write_batch_rows(batch_data) # 写入表头
for col_idx, header in enumerate(headers, start=1):
cell = ws.cell(row=1, column=col_idx, value=header)
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal="center", vertical="center")
excel_writer.close() # 写入数据
for row_idx, item in enumerate(data_list, start=2):
for col_idx, header in enumerate(headers, start=1):
value = item.get(header, "")
print("数据已成功写入Excel文件!") # list / dict 类型转成 JSON 字符串,避免写 Excel 报错
if isinstance(value, (list, dict)):
value = json.dumps(value, ensure_ascii=False)
# bool 转成 true/false 字符串,也可以保留 True/False
if isinstance(value, bool):
value = str(value)
ws.cell(row=row_idx, column=col_idx, value=value)
def get_req_id(): # 自动设置列宽
url = "https://openapi.aidso.com/openapi/ywt/geoReqList?phone=18900000010&begin=2026-03-10 00:00:00&end=2026-03-10 23:59:59" for col in ws.columns:
max_length = 0
col_letter = col[0].column_letter
payload={} for cell in col:
headers = { value = cell.value
'Authorization': '' if value is not None:
} max_length = max(max_length, len(str(value)))
response = requests.request("GET", url, headers=headers, data=payload) ws.column_dimensions[col_letter].width = min(max_length + 2, 50)
return response.json().get('data') # 保存
wb.save(output_path)
import csv def get_main_domain(url: str) -> str:
"""
提取 URL 主域名,支持 com.cn、co.uk 这类后缀。
"""
if not url:
return ""
def to_csv(): ext = tldextract.extract(url)
query_list = bh_utils.query_data(
"select * from geo_commit_task where reqId in ('402e0366-415f-46b4-8a5e-be270679d5c0','764554d3-148b-420e-86a2-40dd83d062ba','f761258d-2372-469a-bda3-1cb3b881c4a0','e78416ce-5c83-4a85-a18c-32e4916e9250','37ae17aa-270e-4a32-97b6-86aa691d57a6','bea11246-12d5-40f3-8a70-e71d0074862a','04d9dcea-8ca7-4a1c-8196-f91ae8fd0633','c2d1f6b4-aa13-4827-994c-19820e90f5ae','df0d72b4-8d43-4761-bf8f-40dfe2516943','5bda7418-ab5e-46b4-9e36-6d0a770201de','f08d91b9-58c5-4a21-a001-0b5c6e13bae1','dcaaced7-9259-40e9-b23d-7d62b46139ef','032cf0e5-92a0-448f-ab5f-5986e5cb16b3','f9ae9c57-c3f3-4446-be78-9f8af2ff5270','fa28ef1c-ca4b-4d86-a1d2-7d0f8cb8a0ca','d9d5001b-f5da-49e4-be58-d722d671fabb','3b490bcb-002e-486d-9e1e-a2058879dd4e','e12ad0f7-3b60-439a-a322-6d8012f3a742','73d31139-3b35-41eb-9550-848635c865c8','bda4126c-b392-4c0b-a2e9-fc2e28af2b46','344e96bf-fd18-4218-9367-0f723a1aa4ee','9a76d464-e628-46c9-bd69-6ea6a503e312','3935c16d-5eea-4370-ac3c-bba3ff95119f','b458576b-dda4-4aaf-bf72-70325f509b92','a0e28647-ddaf-426d-b1e3-f32cc00dd54a','1d28f8f7-9e94-47e5-90e8-85b6970e4699','5b6eaaa9-927a-4a4a-9ef1-0e85f3eefe7a','5b774d87-a3b1-4b31-b702-dd7681460127','1449ab66-16c0-4a68-8106-2c11dbf63d0e','9149ec81-df0c-4f96-94aa-9f5f2b5c7629','65db6517-1b89-4cff-8305-cde546442ad1','bb8f2c88-df8c-4634-95d0-ed04d710f1c6','4a3c21e9-dd9b-48da-8e4d-697216434b4f','d4d68a65-c0dc-46f4-92a7-970be2935d6b','0bbbded6-a1cc-4d3c-82da-48533cf9976c','0f54581f-7d98-4d9f-a1d2-66da6cc6d5a9','43640355-f350-42fb-9d02-d70ffeedfdc8','8a990c73-13c8-4669-aa36-79553decca0c','02a18ed9-e22c-4ed7-a3b2-31e4349de211','c5f20520-e3e2-4b9a-9e29-bdb3d0defc1a','e816140e-6c19-477b-a100-97674b619cf2','001aa067-3444-49e7-8358-b71e4186393f','de784e81-08d6-425b-8375-7d0a2d83313d','b5f279a5-d616-4aea-a757-139090f147a4','a8ee8ff9-3744-4d7f-af8a-a0f63c415455','88644b3f-090d-45f1-9be1-a385b207ecda','6270cd9f-1786-4dd0-9f2d-66e7a73b6a00','661feb8c-eca4-49a0-a654-e8963e86cec5','1cc7dce2-b853-49b0-9d76-c8ef2c8f60e2','7ec90953-8be1-4d7d-a4b6-7925675564b8','c5b0297d-a296-4fff-a9f5-2f18324f6393','bd35adfa-dc9a-4bfb-bb5b-ea1d8723c38b','a117e7fd-6438-4309-a8e5-43b7203fcb13','b9d5931a-af54-41e8-b632-d1a75bb845e9','6d04a745-cfa3-4b69-b9bb-6e153fbcbde3','5a0e6049-a195-4bef-aa6e-6fc4e5cd3237','4c26570f-e217-4a08-97d2-2962cc535278','14cdc028-792a-4e14-b6a4-d43eac4fad3e','027e1685-df78-4820-93a1-aa68921ccaa4','51792899-0d97-450f-8828-38308702117c','fc96735e-9a62-4bea-8045-bbe6e13b9ce8','8ebd2872-e80d-48d5-935b-410a56352d68','38015432-15a2-42d9-86aa-3f7378501749','a4fa61e9-4b5c-4d37-839c-53fa49900d90','960914c9-8964-4d04-98be-61a8540aeaf8','a2c2cb76-ac37-4ee8-8d1c-2fe2351c6e6d','71b4811f-6d9e-4d57-941b-3795ed13685a','2147559e-bb61-43dd-8c9f-665c53d65f7f','a2153afa-7f13-453e-adc9-c88d1acbad91','a26d4823-1ff6-4b9f-b605-d8a652a5803f','425bc4bd-7862-4a9e-a54d-e5021f2410d0','7988a5ab-5d4b-444e-ae65-aacc10778cdb','60c5acee-f379-4b5a-9984-22e9647c9c41','fb01506a-da7d-4c5d-bfa6-41c88bcde201','b5ca42c7-4153-4976-a45e-669168b4f10f','dfeac8c6-2694-495a-bebf-f65cdd4a3cdf','4d759901-3df3-48ee-8301-9cd2f701102c','85446bdb-78b7-4124-b4bf-662f3a56d7c4','d9c5dbf1-7a85-4a5e-855f-422dc3242505','7d96a681-0a2b-4d9e-a3b4-776d12df61f7','e6a44084-65bf-489a-9f13-a39e7a75e52e','2d0b76fd-7b10-4cc5-8b85-6bf75d3c2176','2076564f-f3c0-475d-b03d-87a726e8b2e8','656be388-a590-4a89-b7f0-a93e9beb09e2','2d6f0298-fd1e-493f-bb33-3c7b4b126094','21b9f675-1c98-497f-aebb-545b64aaae5f','00367916-4f52-4a0d-bdac-a480fa15f5dd','67ec62d2-9b64-4040-8176-1d51b7501933','68ce2fa4-79a6-4ce5-987a-50f8a11a55c9','e32c763c-e382-4b2e-a1fd-20267db7535d','856ac9cc-4e01-4609-8da7-f69dadc0ec01','f24b7fa3-edd9-4380-868e-436873153628','9dcd94e4-add7-4738-93d8-cb04ae135cdf','bf58bc69-7022-43c6-b7ae-e50b7bc8e3b3','0ab321f8-8104-4cdb-9eda-d3910e828f78','f633be11-21b3-465f-9152-df80eb0aa7f5','0d2e9e81-7187-40f8-880f-d443fdf3bba1','4f517d93-573f-4490-b797-d569939fe93c','daca5655-e7e7-445e-999c-8b95c748c26d','5b98ba7e-d012-4297-9f1d-060c5f03ab20','2f13a859-dc2a-4ffe-8a90-644a3bb200fd','977492ff-923e-40b8-8789-c96a41a3040a','103c4022-48ce-4821-b063-22f79490a094','7f1986d0-84d8-4155-b561-5570c0db2f3e','1af9153b-0fe4-4c60-a906-73414622cbbe','719085c7-5e76-4ab3-b1dd-c837342ab56c','e129687d-003b-43be-a2ad-4b00beb34742','09394f10-bf38-4176-b0e5-ba14faa209bc','b5e775ab-f12e-40b6-9c17-e6c06cd9fd73','96ce8651-ce30-4e08-9747-fb2d18738afd','e8931f38-302e-4ec2-a99f-777f8262b0fd','b566da9d-25f6-4ac9-82f4-12ad66b59169','898550c7-f9b3-4072-8381-3f98cdabe447','385f6213-f427-4e05-8c55-e21cc13aedac','9346b336-b594-40eb-b032-f389f83cf2ec','9197e1c9-e115-4ec0-b934-e8090c4d8294','fbbb1fa7-d009-4b87-90b6-5fc9b061460f','03c52d6f-6694-4634-a6a3-76a110b2f75e','7f901ea0-b429-4c70-87ec-4849c0f241be','ce553bf9-84ad-475b-9208-65d727587811','e7cabdae-3bbd-4ff6-8b20-f54c7b10cf4e','f6e250ac-74f3-4665-a085-17d2272ef8a7','c18629ff-225e-42b8-a0e3-db4b614c361c','94b69431-3122-4bc6-8b59-0fd965ca8a55','57343d82-4701-49f5-b2f4-95776a5e491a','396159bf-4732-4a72-93f8-98b41671935f','6270d631-cfac-4fb7-a3cc-a5239c167369','8d9534a6-2262-4b41-a397-1cb5109c1e4d','00c0727f-bcf9-43cf-b827-c1cbe8fd4f89','8e4b4498-d52a-4dab-a3c9-008f5c36bb54','38a0b7c0-7d89-4508-9e93-b92146f0f37f','614daa6c-af87-40bd-83db-f48fc5e6b947','e6d331ec-f3a1-4eb4-a0c7-678893c6336d','1d5f705e-13da-402f-9ef4-fe6223534304','8ab68210-44da-42da-b66f-a9980baed8d6','71342621-08cc-436a-8b7e-d2b362009d6b','59f95902-93ff-467a-8087-1fb358ce6893','e3f67cc0-9fce-4102-80b8-1a6eb55d623b','9a8c9969-16a3-4ba1-8fe1-d981715ec882','11cf203c-ba8b-4794-87f4-df41edd82d4d','a0a6805e-2776-42ee-9185-3d55042c158c','6f67ec51-cc55-4f1e-b9df-5803c1b96104','72e96887-0bf8-4a7a-ad96-9ce37a460c61','9afe5f96-295b-487e-b120-d9688a92eae6','98540dbe-cb8e-4549-a57e-e6f5bd4ab705','1e8a95a5-01cf-4cb5-86d8-afffe27689e6','cdae4810-9ce1-4ac7-b820-0cc678b2182f','10c7d292-fa7e-4b68-a746-ca45f6da6967','78521cef-f7d8-4d37-b104-fcad04113244','78cfc55c-29c0-4c02-be86-41ec48f15026','5e737176-8fe8-48c9-8732-4bd75e274869','8e323e60-1784-4274-adea-191cd75b77c5','a343d700-ae56-4b3a-b71b-9f11a09e0f59','ae54a8dd-6348-4b2f-80d2-20143732f28c','b550b730-4848-490a-acdd-075c787e7f61','217fad3b-c0ad-4d17-b334-9f7d5b17d02c','899157b6-672c-4280-af5d-b48b78437d11','98147978-f334-4ff5-8e32-3389ce495756','d08a0c3d-522c-4fe9-8d8a-ddffdb04bfa7','32720b8a-abe9-4833-913b-66b9e6821d72','42056a6d-9fb1-4d71-81af-5b5eb653b427','a37fb18a-3a61-4843-95c2-9598d5f3303d','b76f8068-9f94-431a-8398-7cadb933c0d9','c400c60a-f5dc-4879-b103-a7b67440d5c3','4d4bbc07-6fa9-490f-aa0f-1958247650f2','c8e1f75d-d882-42ee-88a9-e89f2da85700','442732cc-76b3-444c-9af4-c410adb3570a','065d4f3a-098c-437a-912f-2d3020ef2950','ef3ebb13-a965-40d4-90c9-e2109c532e60','6b44c62d-dfc2-4f2f-8658-35b1bc977739','fddccf26-d822-4c23-baeb-f9c98a5bb199','bcd6049e-9853-4bd8-a9b3-4f783db1b0b2','1d7c519c-0b2c-46ef-a29c-c09cde85bac3','519ccbe6-e38e-4f02-bfbc-6bed858207e7','43d45a2d-82ac-49dc-9117-93cc48efb7eb','55bddac9-92b0-4518-b278-2f90cde0cb22','18e59a0c-5426-43cf-9e72-9bc712ced6d7','b33e4dff-2527-4b14-881f-cbd63819268b','4ef0e57c-ffa9-4d36-8127-4fcddfdbc389','dcbeef9c-8b0e-46cb-ba82-88486f4395ff','758013c5-73a8-42cc-9308-be027d5345d9','d466aee5-c550-4cb6-af7d-5e1bfa8d5f6f','0d032268-910d-4643-ab06-366741aaef8d','1b62afdd-cabb-4fae-8513-03d0e35cedb0','83da0acd-0db1-462f-aa7e-735140e812aa','3167562b-8460-4b72-b4b2-497a77a7a6cf','32df6d21-8663-42d9-81b7-deee4a009364','0d679eca-3c07-457f-9222-876e9bb084d7','489ccce8-0a57-4505-9cad-362c03df4f26','8226381d-9db5-497b-bbd0-fc14dd8b38d9','42bf91dd-8eb1-47a2-8caa-a878bb278243','85532823-9832-419e-ae17-8204d763b24a','67e0c670-8059-4d80-8d54-4dcfd31ba497','94d54f8a-cd38-43ca-b014-7a16fe11b180','f904ad94-0abf-4d51-9c66-6d49a2daccf2','2d55dc16-4229-4180-8c03-598641929495','1f548c43-bdc6-4e36-aa90-a889c9fd2e60','66db16dd-5fb1-4da3-a11b-e99a4632dc80','158fb147-3068-41a9-8cdb-e80c53e9d07a','b7b5e7b3-09ba-4941-b760-54b95d76c500','b9bb6409-cb61-4295-bcf6-c23956634a13','192c1924-0cb5-4e6f-abd7-c39608393a71','198f6cb9-23aa-47d5-a9b8-1334e8047e0e','5d6a29ed-f088-40cc-a828-798b9481ec5e','f6f1882a-5a2a-413a-bcc8-15c5a30c5665','00cf8877-321a-4908-a63c-ea748ec4c7b2','7275a6e4-7c1e-480d-88fa-68f59a7066c2','515b6157-40b4-4092-bbd2-89c83dc6ee63','5ba1e3cb-e7f9-427e-8ce8-ed7eeda37397','39c7ce59-a0f5-4cd1-9645-4aa9212ef96d','2dc5d866-107a-4f7e-8514-9ed2bdf35543','b3bd0a0f-985c-4e5d-ae96-ffa0c4beb16f','05cc4549-97de-4ee1-a4e4-4a6c4d8e3b13','c3b72930-468f-44d0-b522-598bc4db0fa8','0a89723e-3733-4031-b9cc-6bbba105fb45','39282ff2-ca9e-4039-905f-9146f71bc363','e12dfb28-5fff-4a60-adba-8979333bb37d','79af884e-f3f8-46b3-96e1-c603e543dcd2','de3bb456-667e-4ee4-bd13-1c2e0dee31cb','049c48e4-8910-4bb9-af63-a5e223aae60a','bc836645-650c-41d3-8fe7-7be54a67260d','a03ac9a9-385c-48a7-8e9d-1682f7476086','993a7ce1-6db4-4ba5-a8e9-a89ec7090aac','48bbf7cd-2c23-4a05-8e7b-b284c6ff9072','5155e653-01da-4e07-b8fc-b2b8cbf370b4','44216d61-62e9-43c4-a81f-456a788500f5','a9467f8f-4a60-4467-a232-a697ce73bdf5','8aba38e4-44a4-4079-a9fe-ac36e9f5ace8','d781e2e1-2d63-45cf-946a-219f86996314','1a4f306b-f889-477b-9c76-f6e131e72748','bd171dd3-0ecc-4b7d-911b-703345fa7d03','e191cacf-e5ff-4dc4-84db-a2a9952434b9','f4dbceaf-5313-47e0-9643-acf2a9a69952','18363a0b-e51f-4ae2-a726-15210aca2c32','f8f7e9e0-3cd3-4311-962b-5f45d5318175','83d2ea2a-5ae8-4608-8aa2-8023fcd5dfcb','4aaba832-1711-489f-9e91-3bd3ab49ec78','9208c6e4-0fbe-4597-8db3-8b641a27ede6','4bcfe7c6-fa8c-4d43-8427-92b2c6db242e','9932df53-8dcc-4160-b576-3da316b094f4','d55bc555-c299-4072-b535-b469ddf8ea9b','cfb23850-8476-4429-8b7d-8dd5386c7ad4','71b4750f-8f90-4841-8cfb-da5796729b33','7ced1030-f0fe-4c07-9623-443134159f52','0142509c-b715-4d1e-a897-99c7f68e1f72','8f64327a-7bf4-4cbc-a0cf-94c10944e8dd','ef49cdc0-6417-4421-b394-7ee31ff1de19','fe194aac-1576-47c7-8cb2-9634067613d5','3a5bdd7a-90de-46bc-8d4d-d8592eac7a8f','a1a31039-bd3b-4eef-8d12-a00422be8b34','04e54df4-811a-452d-a937-28da81fcc57e','5f54e4a8-597b-44de-9cdd-e677bec40b5f','0e4e9035-89a7-4b3d-8300-6ae82f329f99','9a4bdc4a-38b2-4341-acc8-88614863471c','24deb343-baec-4546-978f-d82daa2a84ac','0ad4128c-8bef-4506-95de-0ea10d6b3777','9a1b465d-07f8-4e6d-a353-96fbfc2ab319','4957f366-3893-4e27-9fc2-14801ad5c4ef','14cf293b-b5d4-4228-a54a-249558502b1c','1a580eec-31a2-44d7-8947-e166e8785fdd','b853a74e-f897-4943-9d70-fc6ae46eacc5','eff899e6-d27e-40fd-bad6-0bd89716f136','7ae93cbb-c50e-471d-8607-511c11695e3b','6b8a6e25-ee7c-4158-b2bd-688a3adaee19','3fca39b5-88b3-4ad6-8782-88f969df3906','a00555e0-c35f-485d-ba34-e59ce065b659','b970689a-b7e1-489d-94b9-31a901dae834','55faec72-5f02-40e7-81a3-a8bfbebf556f','8e8c354f-fd9c-4fe4-a55e-414060586e25','aaf9e60d-8d3e-426b-94b5-f052860d10b8','730a9da6-da00-4eb1-b8d7-34b1f226b654','341fa26d-ce5a-4763-9ca2-31104741659b','ca2a39f8-1281-4a42-a07d-dbf77c89c5b1','8cab18e1-5b16-4692-a272-eaa7cf814534','79bb416a-acc7-40f1-8699-7a57e7861d05','8c6fa91f-18ba-4e8a-b29b-1fe30414ab1f','ba6a410a-e746-4447-90a9-b7699f67304d','51826d85-4f83-4dd6-87c2-c754e8deb2f9','b057359d-41a3-46ce-88de-473da52d9db3','dda83cc1-23aa-49ef-b3fc-9b1f94342005','bf50de19-bb93-415f-8fb9-0db610c998ed','22012d9f-8405-4873-8814-784a1df3e0c6','c437bc38-31c2-47b9-8d00-cdbda2a1c6c5','2c743e2e-d80b-4b9e-8bc2-932a7e4c756c','c855307e-134c-41fe-99d0-7a650d81dc3b','b8da3a75-8d0b-4745-b03d-0fb87472ae48','046fc7a4-7fd0-4513-ac06-3006de1b614a','b2f5685e-d7a8-4e63-8d21-8ca0aee75f5c','c1473bdb-1ba4-45fa-9f81-14daf32fddb6','7a837f2e-429e-4bee-9abb-f2440a5a0eb3','25cbe593-c7d8-42cb-919c-4ac0b0af3f1a','b3300982-a0e0-4d31-9fa7-ee51ac49b68b','4df7a2f5-4610-43b3-a344-f6fa7f461bee','34ba649e-7d3e-4e6f-9757-139394dd1d94','06f229f4-f998-4584-a704-023c168133ac','5c0c9344-ebe6-4f28-b75e-2dc74a86cfff','9edb6e55-270b-4093-a510-3c46de63e6a4','c4fb2c57-6156-47f1-915b-25995f28c432','4d86e1c7-071d-4a45-a938-0e8c6a377de9','46d6c433-7110-4a25-88f7-cb38ac068879','1696ebff-9b26-44dc-8ec7-197b4beff925','20ab1f06-bd7a-489b-9f91-c40fb5a430ac','268bd57b-f4cf-49d0-817b-65bce1206705','5a136fdb-7fdd-410d-97fe-efdfefe5da0b','20be731a-30d0-4f48-8ab3-3e3cf5a38ab4','37d2d3e6-9e81-4f1f-b373-53c744a745fb','a7afebd5-a6fc-4c23-8089-79f29e2e83b2','3b289fea-dd6f-460d-82d0-0981c7b824d9','af34ddb7-989e-4d88-9f3a-53cbe97d9ad5','635de1cb-9288-4a27-904a-97fb74b4ca6e','d66c2dd3-d404-41bf-8c1f-662c9c3ca38a','01382d0e-85ae-47eb-85ef-cf21d59f066f','c457ac2c-5d26-457c-992c-ad01069b82b0','39b7f038-81f8-4ed6-9fba-c24c1b206010','76ee2cae-9639-45a7-9dbb-002372400835','d3314ed6-07da-4e53-9331-64d6a1155265','01c16eb2-1a7f-4339-a9a7-7edfeb7652a3','f793659b-7c8a-4bb9-8140-c4eca10be7d4','b25e9f3d-d1ad-4672-86bd-094e8231a14f','2d3e3e22-f1f2-45d9-8e4f-6c4f7d9f0271','d7f84b76-66ce-45d9-839c-951ccdf98130','ae49e999-316c-4a06-9a62-6b779a8b4b16','81180b70-f631-4517-8c27-e361cae04ddf','5c516e38-77f2-42f4-b00f-966c2d4dfe77','79b6d29c-9198-4068-a5f3-c5948288c6f7','ee4178ec-25a7-4e68-8dd9-852d2075e3b9','fedc3ba5-d25d-4839-9efd-0525a6aa0f0f','ec4deeb0-afb3-4889-bd3f-f3ec8c450cff','f08156bf-8e35-4ec6-bcfa-73a808c1a160','6477db44-bcd1-4075-a7dc-a675358cebfb','a4be30d4-fa36-459b-b8c9-3622a616ca20','528107ef-7a0c-4d02-9d9a-7a42c1c03993','4d0ae58f-4cee-422a-a04e-ca31ff1aab7a','529835d1-f4ba-41ae-a225-a376c36f93ac','1fac7a2f-ccbb-409a-9c93-3fe7df28bbba','e3337410-4aa1-4105-91f4-17db3aa10350','929386bc-2a53-4cc3-b934-74d7c77c8d3b','67c309b2-fc8d-43a6-86ea-8b45b0acb554','a0e3b82b-5447-444d-8f20-a11dc36a9155','61fd794a-ba5c-45e4-bac8-699e0a6939ca','f11b2aa9-b2d8-461a-9d26-230e77c2b238','9e82fddd-ca84-4d1e-b0a9-a8e1267175cd','971979a2-3b4f-4fe2-ac07-6e7c09a898ef','5f0886ca-507e-4440-91c7-7ad870bf8365','50b1ae80-1154-49fa-8511-430afcc612e1','f4414919-7634-4ef0-80b4-a2414775367e','34c6d5c4-efa3-4281-8664-88a8ffd188b9','fd6c251c-66c3-4188-a0e0-77dc1c7ceb36','45962005-6ec2-482c-8881-7ec3a8984735','dd946f04-8908-469c-a5e6-6e731b836224','d522e7c7-6861-43ec-99dd-60e6fc708c4c','c5674c74-0436-41be-b72f-db0f4fb43083','869ff9fb-d180-4739-9857-56de6907c993','da956072-a90a-4a20-8155-33fa98706852','4b20fa14-dcee-41db-b91a-988daa0b3ded','798c10cd-f463-42b5-adf3-82709753dc2c','14b9f3d3-4a39-4907-a8f3-5f6c8b570630','bf52b1e0-8020-428d-ad1e-c150952c7265','d03d0c3a-f9be-4db8-9376-14df5957be2a','02141813-2726-408f-94e2-7ec5d4d314c7','8bbde9eb-2e3d-42e3-af1b-dee84aef2847','c7541e01-dd20-4fb5-81a9-128ea4d9250d','65371dff-444a-4c66-902b-c300685e7032','d8d05ae1-ca30-46e9-92ab-6a8f579ef1dc','da8959e9-003d-46b2-8ec1-394f12b43246','162a52ce-4576-4d5b-9914-af0bd63210a9','cadc018d-c73b-4c67-9279-0c73ab96a7bf','6dc3c118-ef78-4743-89dd-d61837e0a863','7af46d2b-921a-4b08-a967-096573568423','dac0b5dc-6589-4ae9-b979-d73b3753d2be','0da71820-12ab-4ece-8a38-825b7811bd22','d345f8ab-6ccf-4465-8130-4766d26e205c','a36ba926-3c1f-4988-bfe4-4cdcb98eb451','aa8d245c-14c3-4df6-b749-87fbba333170','d1a78352-b8cd-4944-bc68-b370405b9966','3d388a1a-5982-441c-a0a0-1d83f8f8141a','45dfa128-0280-4332-9ba0-1c6d72e71717','881a07a4-a8db-48bf-8291-300be0be0289','d8d1e9cf-0776-4364-b031-2b1d799457e6','c48b2772-4068-44a9-a3b9-0b60f9b76b34','9dddf2d9-79c5-4a5c-9d08-97d42e1c4bff','66864dac-8b01-4e87-912e-d5572ecc8257','148c22a6-5f84-4432-9e5f-43f046aac4b2','291509ed-2005-4bb3-9492-ee019034de80','bda1bcb3-a237-4d15-894e-22fdd5bc549b','120353c9-57f6-4e58-94f2-a9d35cc3f017','dcebfba0-2a48-467d-a594-ed9ba13dbca5','d6a326b3-4a2d-4f6d-b8d7-e3d09ba17efc','d35b6267-b08f-4d57-bcbd-d2635ad0bddb','4df6ff95-bb27-4d5c-80c4-f13f652bdfd6','a641f3e8-9681-43e2-9fc0-3e7645ae4d58','df289591-2b78-4c36-a914-70d751505d4b','88cbd480-7352-40a0-9129-a605ffded6f0','e5934fff-159a-4b6a-bf45-7f97af8de935','c100490d-f1bd-4365-ba2e-6eee13b39d8e','8fc50723-ec96-4451-8ed8-b62673bd0cc7','4ba1a009-1a2c-4a4a-befa-0af2a7bf0327','7f5ae93f-a533-432b-9b20-35509b8771c1','d9801f34-8f7f-40e0-bc44-ab74969a9b9f','b461f8de-7479-45bf-9276-48d871916d25') and platform in ('DB','TXYB','DOUBA','TYQW') "
)
task_list = [] if not ext.domain or not ext.suffix:
for i in query_list: return ""
task_list.append(
{
"taskId": i.get("taskId"),
"prompt": i.get("prompt"),
"platform": i.get("platform"),
"insertime": i.get("insertime"),
}
)
plat_form_map = { return f"{ext.domain}.{ext.suffix}"
"DP": "deepseek网页版",
"DB": "豆包网页版",
"TXYB": "腾讯元宝",
"TYQW": "通义千问",
"KIMI": "kimi",
"WXYY": "文心一言",
"BDAI": "百度ai",
"DYAI": "抖音ai",
"DOUBA": "豆包安卓版",
"DPA": "deepseek安卓版",
}
csv_path = "/Users/yaowentong/Desktop/欧莱雅_面霜_result.csv" def excel_to_prompt_map(excel_path: str):
wb = load_workbook(excel_path, data_only=True)
ws = wb.active
with open(csv_path, "w", newline="", encoding="utf-8-sig") as f: # 读取表头
writer = csv.writer(f) headers = [
str(cell.value).strip() if cell.value is not None else ""
for cell in ws[1]
]
# 表头 try:
writer.writerow(["prompt", "platform", "context", "quote", "insert_time"]) prompt_id_idx = headers.index("prompt_id")
prompt_idx = headers.index("prompt")
layer_subcat_idx = headers.index("layer-subcat")
except ValueError as e:
raise ValueError(f"Excel 表头缺少必要字段:{e},当前表头:{headers}")
for i in task_list: result_map = {}
taskId = i.get("taskId")
prompt = i.get("prompt")
platform = i.get("platform")
insert_time = i.get("insertime")
context_path = f"geo/{taskId}/{platform}/context.txt" for row in ws.iter_rows(min_row=2, values_only=True):
quote_path = f"geo/{taskId}/{platform}/quote.txt" prompt_id = row[prompt_id_idx]
prompt = row[prompt_idx]
layer_subcat = row[layer_subcat_idx]
if tos_utils.check_file_in_tos(context_path): # 跳过空 prompt
context_text = tos_utils.get_string_from_tos(context_path) if prompt is None or str(prompt).strip() == "":
quote_text = tos_utils.get_string_from_tos(quote_path) if tos_utils.check_file_in_tos(quote_path) else "" continue
writer.writerow([ prompt = str(prompt).strip()
prompt,
plat_form_map.get(platform, platform),
context_text,
quote_text,
timestamp_to_datetime(insert_time)
])
print(f"数据已成功写入CSV文件:{csv_path}") layer = ""
subcat = ""
def to_excel2():
query_list = bh_utils.query_data(
"select distinct reqId,prompt,insertime,platform from geo_third_task where insertime >1770566400 ")
task_list = []
for i in query_list:
task_list.append(
{
"reqId": i.get("reqId"),
"prompt": i.get("prompt"),
"platform": i.get("platform"),
"insertime": i.get("insertime"),
}
)
plat_form_map = {
"DP": "deepseek网页版",
"DB": "豆包网页版",
"TXYB": "腾讯元宝",
"TYQW": "通义千问",
"KIMI": "kimi",
"WXYY": "文心一言",
"BDAI": "百度ai",
"DYAI": "抖音ai",
"DOUBA": "豆包安卓版",
"DPA": "deepseek安卓版",
}
batch_data = [] if layer_subcat is not None and str(layer_subcat).strip() != "":
for i in task_list: layer_subcat = str(layer_subcat).strip()
reqId = i.get("reqId")
prompt = i.get("prompt")
platform = i.get("platform")
time = i.get("insertime")
file = f"geo_snipaste/geo_snipaste/20260209/doubao/{reqId}/{reqId}.json"
context_path = f"geo_snipaste/geo_snipaste/20260209/doubao/{reqId}/context.txt"
quote_path = f"geo_snipaste/geo_snipaste/20260209/doubao/{reqId}/quote.txt"
think = f"geo_snipaste/geo_snipaste/20260209/doubao/{reqId}/think.txt"
if tos_utils.check_file_in_tos(context_path):
batch_data.append(
(
prompt,
plat_form_map.get(platform),
tos_utils.get_string_from_tos(context_path),
tos_utils.get_string_from_tos(think),
tos_utils.get_string_from_tos(quote_path),
json.loads(tos_utils.get_string_from_tos(file)).get('share_url'),
f'https://tcdn.aidso.com/geo_snipaste/geo_snipaste/20260209/doubao/{reqId}/{reqId}.png',
timestamp_to_datetime(time)
)
)
excel_writer = ExcelWriter("/Users/yaowentong/Desktop/美团20260209.xlsx") # 按第一个 - 拆分,例如:提问属性-对比类
if "-" in layer_subcat:
layer, subcat = layer_subcat.split("-", 1)
layer = layer.strip()
subcat = subcat.strip()
else:
layer = layer_subcat.strip()
excel_writer.write_batch_rows(batch_data) result_map[prompt] = {
# "prompt_id": int(prompt_id) if prompt_id is not None and str(prompt_id).strip() != "" else None,
excel_writer.close() "layer": layer,
"subcat": subcat
}
print("数据已成功写入Excel文件!") return result_map
side_map = {
"DP":"Web",
"DB":"Web",
"TXYB":"Web",
"TYQW":"Web",
"KIMI":"Web",
"WXYY":"Web",
"BDAI":"Web",
"DYAI":"App",
"DOUBA":"App",
"DPA":"App",
"TYQWA":"App",
"TXYBA":"App",
}
def get_widget_codes(text: str, extra_code_flag=False):
widget_code_map = {
"render_ecom_card_widget_product_start": 1,
"render_ecom_card_widget_poi_start": 2,
"render_ecom_card_widget_taobao_start": 3,
"render_ecom_card_widget_damai_start": 4,
}
result = []
from collections import defaultdict if text:
def regroup_by_brand(data_list): for keyword, code in widget_code_map.items():
brand_map = defaultdict(list) if keyword in text:
result.append(code)
for item in data_list: # 不是 False,就认为包含 code 5
brand_name = (item.get("brand_name") or "").strip() if extra_code_flag is not False:
if not brand_name: result.append(5)
continue
brand_map[brand_name].append({ return result
"req_id": item.get("req_id"), def get_aidso_data(phone,begin,end,brand_name,platform=None):
"created_at": item.get("created_at") req_list = get_req_id(phone, begin, end)
})
req_time_map = {}
req_brand_map = {}
req_ids = []
for b in brand_name:
for item in req_list:
if item.get('brand_name') == b:
req_id = item.get("req_id")
created_at = item.get("created_at")
req_ids.append(req_id)
req_time_map[req_id] = created_at
req_brand_map[req_id] = b
req_id_sql = ",".join([f"'{req_id}'" for req_id in req_ids])
if platform:
platform_list = ",".join([f"'{p}'" for p in platform])
query_sql = f"select * from geo_commit_task where reqId in ({req_id_sql}) and platform in ({platform_list})"
else:
query_sql = f"select * from geo_commit_task where reqId in ({req_id_sql}) limit 1"
query_list = bh_utils.query_data(query_sql)
result = [] result = []
for brand_name, items in brand_map.items(): if query_list:
result.append({ for q in query_list:
"brand_name": brand_name, print(f"taskId:{q.get('taskId')}-success")
"data": items quote_str = tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/quote.txt")
}) if quote_str:
quto_list = json.loads(tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/quote.txt"))
result_get_req = json.loads(tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/result.json"))
content = tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/context.txt")
rich_media_block = tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/rich_media_block.txt")
rich_media_type = get_widget_codes(content,rich_media_block)
allVos = result_get_req.get('allVos')
brand_str = ",".join([
item["word"] if item.get("brand") == "没有品牌" else item.get("brand", "")
for item in allVos
])
platform_code= q.get('platform')
brand_mention = False
rich_media_present = False
triggered_search = False
if rich_media_type:
rich_media_present= True
if quto_list:
triggered_search = True
if brand_str:
brand_mention = True
r = {
"prompt": q.get('prompt'),
"platform_code": platform_code,
"side":side_map[q.get('platform')],
"quote_count": len(quto_list),
"triggered_search": triggered_search,
"brand_mention": brand_mention,
"brand_names": brand_str,
"answer_length": len(content),
"rich_media_present": rich_media_present,
"rich_media_type": rich_media_type,
# "content": content,
# "quote": quto_list,
# "rich_media_block": rich_media_block,
# "created_at": req_time_map[q.get('reqId')],
# "brand_name": req_brand_map[q.get('reqId')],
}
result.append(r)
return result return result
def get_aidso_data_v2(phone,begin,end,brand_name,platform=None):
req_list = get_req_id(phone, begin, end)
req_time_map = {}
req_brand_map = {}
req_ids = []
for b in brand_name:
for item in req_list:
if item.get('brand_name') == b:
req_id = item.get("req_id")
created_at = item.get("created_at")
req_ids.append(req_id)
req_time_map[req_id] = created_at
req_brand_map[req_id] = b
req_id_sql = ",".join([f"'{req_id}'" for req_id in req_ids])
if platform:
platform_list = ",".join([f"'{p}'" for p in platform])
query_sql = f"select * from geo_commit_task where reqId in ({req_id_sql}) and platform in ({platform_list})"
else:
query_sql = f"select * from geo_commit_task where reqId in ({req_id_sql})"
query_list = bh_utils.query_data(query_sql)
if __name__ == '__main__': result = []
... if query_list:
get_req_id() for q in query_list:
print(q.get('taskId'))
# redis_client4 = init_redis4() quote_str = tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/quote.txt")
# list_2 = ['想喝李山山,哪里有大额券使用'] if quote_str:
# print(redis_client4.scard("mt_third_task")) quto_list = json.loads(tos_utils.get_string_from_tos(f"geo/{q.get('taskId')}/{q.get('platform')}/quote.txt"))
# query_list = bh_utils.query_data(
# "select distinct reqId from geo_third_task where insertime >1770566400") platform_code= q.get('platform')
prompt= q.get('prompt')
# for i in query_list: for quto in quto_list:
# req_id = i.get("reqId") quote_url = quto.get('url')
# file = f"geo_snipaste/geo_snipaste/20260209/doubao/{req_id}/{req_id}.json" quote_title = quto.get('title')
# content = json.loads(tos_utils.get_string_from_tos(file)).get('content') quote_site_name = quto.get('site_name')
# doubao_process_original_data(file, content) quote_index = quto.get('index')
# to_excel2() quote_published_at = quto.get('published_at')
# list_keyword = ['淡马茶坊怎么点更便宜','奈雪的茶怎么点更便宜','东方墨兰怎么点更便宜','馬伍旺饮料厂怎么点更便宜','Blueglass酸奶怎么点更便宜','春莱怎么点更便宜','茶话弄怎么点更便宜','陈多多怎么点更便宜','树夏怎么点更便宜','李山山怎么点更便宜','GridCoffee怎么点更便宜','阿水大杯茶怎么点更便宜','绿茶餐厅怎么点更便宜','达美乐怎么点更便宜','淡马茶坊怎么薅羊毛','奈雪的茶怎么薅羊毛','东方墨兰怎么薅羊毛','馬伍旺饮料厂怎么薅羊毛','Blueglass酸奶怎么薅羊毛','春莱怎么薅羊毛','茶话弄怎么薅羊毛','陈多多怎么薅羊毛','树夏怎么薅羊毛','李山山怎么薅羊毛','GridCoffee怎么薅羊毛','阿水大杯茶怎么薅羊毛','绿茶餐厅怎么薅羊毛','达美乐怎么薅羊毛','想喝淡马茶坊,哪里有大额券使用','想喝奈雪的茶,哪里有大额券使用','想喝东方墨兰,哪里有大额券使用','想喝馬伍旺饮料厂,哪里有大额券使用','想喝Blueglass酸奶,哪里有大额券使用','想喝春莱,哪里有大额券使用','想喝茶话弄,哪里有大额券使用','想喝陈多多,哪里有大额券使用','想喝树夏,哪里有大额券使用','想喝李山山,哪里有大额券使用','想喝GridCoffee,哪里有大额券使用','想喝阿水大杯茶,哪里有大额券使用','想喝绿茶餐厅,哪里有大额券使用','想喝达美乐,哪里有大额券使用','淡马茶坊无门槛红包怎么领','奈雪的茶无门槛红包怎么领','东方墨兰无门槛红包怎么领','馬伍旺饮料厂无门槛红包怎么领','Blueglass酸奶无门槛红包怎么领','春莱无门槛红包怎么领','茶话弄无门槛红包怎么领','陈多多无门槛红包怎么领','树夏无门槛红包怎么领','李山山无门槛红包怎么领','GridCoffee无门槛红包怎么领','阿水大杯茶无门槛红包怎么领','绿茶餐厅无门槛红包怎么领','达美乐无门槛红包怎么领','淡马茶坊能领的最大面额红包是多少','奈雪的茶能领的最大面额红包是多少','东方墨兰能领的最大面额红包是多少','馬伍旺饮料厂能领的最大面额红包是多少','Blueglass酸奶能领的最大面额红包是多少','春莱能领的最大面额红包是多少','茶话弄能领的最大面额红包是多少','陈多多能领的最大面额红包是多少','树夏能领的最大面额红包是多少','李山山能领的最大面额红包是多少','GridCoffee能领的最大面额红包是多少','阿水大杯茶能领的最大面额红包是多少','绿茶餐厅能领的最大面额红包是多少','达美乐能领的最大面额红包是多少','淡马茶坊外卖如何减免配送费','奈雪的茶外卖如何减免配送费','东方墨兰外卖如何减免配送费','馬伍旺饮料厂外卖如何减免配送费','Blueglass酸奶外卖如何减免配送费','春莱外卖如何减免配送费','茶话弄外卖如何减免配送费','陈多多外卖如何减免配送费','树夏外卖如何减免配送费','李山山外卖如何减免配送费','GridCoffee外卖如何减免配送费','阿水大杯茶外卖如何减免配送费','绿茶餐厅外卖如何减免配送费','达美乐外卖如何减免配送费'] quote_snippet = quto.get('snippet')
# query_list = bh_utils.query_data( domain = get_main_domain(quote_url)
# "select * from geo_third_task where insertime >1770480000 and prompt in ('淡马茶坊怎么点更便宜','奈雪的茶怎么点更便宜','东方墨兰怎么点更便宜','馬伍旺饮料厂怎么点更便宜','Blueglass酸奶怎么点更便宜','春莱怎么点更便宜','茶话弄怎么点更便宜','陈多多怎么点更便宜','树夏怎么点更便宜','李山山怎么点更便宜','GridCoffee怎么点更便宜','阿水大杯茶怎么点更便宜','绿茶餐厅怎么点更便宜','达美乐怎么点更便宜','淡马茶坊怎么薅羊毛','奈雪的茶怎么薅羊毛','东方墨兰怎么薅羊毛','馬伍旺饮料厂怎么薅羊毛','Blueglass酸奶怎么薅羊毛','春莱怎么薅羊毛','茶话弄怎么薅羊毛','陈多多怎么薅羊毛','树夏怎么薅羊毛','李山山怎么薅羊毛','GridCoffee怎么薅羊毛','阿水大杯茶怎么薅羊毛','绿茶餐厅怎么薅羊毛','达美乐怎么薅羊毛','想喝淡马茶坊,哪里有大额券使用','想喝奈雪的茶,哪里有大额券使用','想喝东方墨兰,哪里有大额券使用','想喝馬伍旺饮料厂,哪里有大额券使用','想喝Blueglass酸奶,哪里有大额券使用','想喝春莱,哪里有大额券使用','想喝茶话弄,哪里有大额券使用','想喝陈多多,哪里有大额券使用','想喝树夏,哪里有大额券使用','想喝李山山,哪里有大额券使用','想喝GridCoffee,哪里有大额券使用','想喝阿水大杯茶,哪里有大额券使用','想喝绿茶餐厅,哪里有大额券使用','想喝达美乐,哪里有大额券使用','淡马茶坊无门槛红包怎么领','奈雪的茶无门槛红包怎么领','东方墨兰无门槛红包怎么领','馬伍旺饮料厂无门槛红包怎么领','Blueglass酸奶无门槛红包怎么领','春莱无门槛红包怎么领','茶话弄无门槛红包怎么领','陈多多无门槛红包怎么领','树夏无门槛红包怎么领','李山山无门槛红包怎么领','GridCoffee无门槛红包怎么领','阿水大杯茶无门槛红包怎么领','绿茶餐厅无门槛红包怎么领','达美乐无门槛红包怎么领','淡马茶坊能领的最大面额红包是多少','奈雪的茶能领的最大面额红包是多少','东方墨兰能领的最大面额红包是多少','馬伍旺饮料厂能领的最大面额红包是多少','Blueglass酸奶能领的最大面额红包是多少','春莱能领的最大面额红包是多少','茶话弄能领的最大面额红包是多少','陈多多能领的最大面额红包是多少','树夏能领的最大面额红包是多少','李山山能领的最大面额红包是多少','GridCoffee能领的最大面额红包是多少','阿水大杯茶能领的最大面额红包是多少','绿茶餐厅能领的最大面额红包是多少','达美乐能领的最大面额红包是多少','淡马茶坊外卖如何减免配送费','奈雪的茶外卖如何减免配送费','东方墨兰外卖如何减免配送费','馬伍旺饮料厂外卖如何减免配送费','Blueglass酸奶外卖如何减免配送费','春莱外卖如何减免配送费','茶话弄外卖如何减免配送费','陈多多外卖如何减免配送费','树夏外卖如何减免配送费','李山山外卖如何减免配送费','GridCoffee外卖如何减免配送费','阿水大杯茶外卖如何减免配送费','绿茶餐厅外卖如何减免配送费','达美乐外卖如何减免配送费')") r = {
# result_list = [] "prompt": prompt,
# "platform_code": platform_code,
# for i in query_list: "quote_url":quote_url,
# prompt = i.get("prompt") "quote_title": quote_title,
# result_list.append(prompt) "site_name": quote_site_name,
# "quote_index": quote_index,
# diff_b = list(set(list_keyword) - set(result_list)) "published_at": quote_published_at,
# print(diff_b) "domain": domain,
"snippet": quote_snippet
# to_excel("result") # "content": content,
# data_list = get_req_id() # "quote": quto_list,
# list = regroup_by_brand(data_list) # "rich_media_block": rich_media_block,
# for i in list: # "created_at": req_time_map[q.get('reqId')],
# print(i) # "brand_name": req_brand_map[q.get('reqId')],
# print('----') }
# print('----') result.append(r)
# print('----') return result
# to_excel()
# process_batch() if __name__ == "__main__":
# excel_map = excel_to_prompt_map(
\ No newline at end of file excel_path="/Users/yaowentong/Desktop/shuju.xlsx"
)
phone = 13810898434
begin = "2026-06-04"
end = "2026-06-05"
brand_name = ['国内AI平台研究【1】','国内AI平台研究【2】']
# print(excel_map)
aidso_result =get_aidso_data_v2(phone,begin,end,brand_name)
for aidso in aidso_result:
# aidso_excel_data = excel_map[aidso.get('prompt')]
aidso_excel_data = excel_map.get(aidso.get('prompt'),{})
aidso["prompt_id"] = aidso_excel_data.get('prompt_id','')
aidso["layer"] = aidso_excel_data.get('layer','')
aidso["subcat"] = aidso_excel_data.get('subcat','')
# write_list_dict_to_excel(
# data_list=aidso_result,
# output_path="/Users/yaowentong/Desktop/aidso_result_v2.xlsx"
# )
#
all_file = f"/Users/yaowentong/Desktop/aidso_result_v2.txt"
with open(all_file, "w", encoding="utf-8") as f:
for item in aidso_result:
f.write(json.dumps(item, ensure_ascii=False) + "\n\n\n")
import json import json
from flask import request, jsonify, Flask,Blueprint from flask import request, jsonify, Flask,Blueprint
import requests import requests
import lark_oapi as lark
from lark_oapi.adapter.flask import *
from lark_oapi.api.im.v1 import *
from aidso_geo.core.down_load_bot import get_platforms, get_all_word_rank, get_sentiment_overview, \
get_platforms_sentiment, get_url_top40, get_site_category, get_quote_mention_word_cloud, get_quto_statistics, \
get_refer_rate_heatmap
from aidso_geo.core.feishu_snipaste import init_redis4, send_message, webhook_snipaste from aidso_geo.core.feishu_snipaste import init_redis4, send_message, webhook_snipaste
from aidso_geo.utils import bh_utils, tos_utils from aidso_geo.utils import bh_utils, tos_utils
...@@ -20,6 +27,203 @@ def run_webhook_snipaste_async(prompt_list): ...@@ -20,6 +27,203 @@ def run_webhook_snipaste_async(prompt_list):
except Exception as e: except Exception as e:
logger.exception(f"异步执行 webhook_snipaste 失败: {e}") logger.exception(f"异步执行 webhook_snipaste 失败: {e}")
import json
import requests
from flask import request, jsonify
# 这里换成你自己的飞书应用 App ID / App Secret
FEISHU_APP_ID = "cli_aaac8fa146fadbd5"
FEISHU_APP_SECRET = "N5omKg6d3sHi3JEIopQ8lcDAZKOiaNQ4"
# 你的飞书卡片 ID
FEISHU_CARD_TEMPLATE_ID = "AAqNYXIaKEOKR"
def get_tenant_access_token():
"""
获取飞书 tenant_access_token
"""
url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
payload = {
"app_id": FEISHU_APP_ID,
"app_secret": FEISHU_APP_SECRET
}
try:
resp = requests.post(url, json=payload, timeout=10)
data = resp.json()
if data.get("code") != 0:
raise Exception(f"获取 tenant_access_token 失败: {data}")
return data.get("tenant_access_token")
except Exception as e:
logger.exception(f"获取 tenant_access_token 异常: {e}")
raise
def send_feishu_template_card(chat_id):
"""
发送飞书卡片搭建工具配置好的模板卡片
卡片 ID: AAqNYXIaKEOKR
"""
token = get_tenant_access_token()
url = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id"
# 模板卡片 content
content = {
"type": "template",
"data": {
"template_id": FEISHU_CARD_TEMPLATE_ID
}
}
payload = {
"receive_id": chat_id,
"msg_type": "interactive",
"content": json.dumps(content, ensure_ascii=False)
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json; charset=utf-8"
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
data = resp.json()
if data.get("code") != 0:
logger.error(f"发送飞书模板卡片失败: {data}")
return data
except Exception as e:
logger.exception(f"发送飞书模板卡片异常: {e}")
raise
def parse_message_text(message):
"""
解析飞书 text 消息内容
message.content 是字符串,需要 json.loads 一次
"""
content_str = message.get("content", "{}")
try:
content_json = json.loads(content_str)
except Exception:
content_json = {}
text = content_json.get("text", "")
return text
def send_message_v2(container_id,message):
token = get_tenant_access_token()
url = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id"
payload = {
"receive_id": container_id,
"msg_type": "text",
"content": json.dumps({
"text": message
}, ensure_ascii=False)
}
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=json.dumps(payload))
@feishu_app.route("/feishu/event/callback", methods=["POST"])
def feishu_event_callback():
try:
body = request.get_json(force=True)
except Exception as e:
logger.exception(f"解析 JSON 失败: {e}")
body = {}
if body.get("type") == "url_verification":
return jsonify({"challenge": body["challenge"]})
# 5. 获取事件类型
event_type = (
body.get("type")
or body.get("header", {}).get("event_type")
or body.get("event", {}).get("type")
or "unknown"
)
# 6. 收到群里 @ 机器人消息
if event_type == "im.message.receive_v1":
try:
event = body.get("event", {})
message = event.get("message", {})
chat_id = message.get("chat_id")
chat_type = message.get("chat_type")
message_id = message.get("message_id")
message_type = message.get("message_type")
text = parse_message_text(message)
# 只处理文本消息
if chat_id and message_type == "text":
send_feishu_template_card(chat_id)
else:
logger.warning("不是 text 消息,或者 chat_id 为空,不发送卡片")
except Exception as e:
logger.exception(f"处理 im.message.receive_v1 失败: {e}")
# 无论内部是否报错,都先返回成功,避免飞书重复推送
return jsonify({
"code": 0,
"msg": "success"
})
# 7. 收到卡片点击 / 表单提交回调
if event_type == "card.action.trigger":
try:
event = body.get("event", {})
action = event.get("action", {})
chat_id = event.get("message", {}).get("chat_id")
# 表单值
form_value = action.get("form_value", {})
platdorm_list = form_value.get('platdorm_list')
promp_list = form_value.get('promp_list')
logger.success(json.dumps(form_value, ensure_ascii=False, indent=2))
logger.success(f"platdorm_list{platdorm_list}")
logger.success(f"promp_list{promp_list}")
send_message_v2(chat_id,"----开始执行-----")
# 这里后续可以写你自己的业务逻辑
except Exception as e:
logger.exception(f"处理 card.action.trigger 失败: {e}")
return jsonify({
"code": 0,
"msg": "success"
})
# 8. 其他事件统一返回成功
logger.success(f"未处理事件类型: {event_type}")
return jsonify({
"code": 0,
"msg": "success"
})
@feishu_app.route("/feishu/webhook", methods=["POST"]) @feishu_app.route("/feishu/webhook", methods=["POST"])
def webhook(): def webhook():
data = request.get_json(force=True) data = request.get_json(force=True)
...@@ -72,6 +276,8 @@ plat_form_map = { ...@@ -72,6 +276,8 @@ plat_form_map = {
"DYAI": "抖音ai", "DYAI": "抖音ai",
"DOUBA": "豆包手机版", "DOUBA": "豆包手机版",
"DPA": "deepseek手机版", "DPA": "deepseek手机版",
"TYQWA":"通义千问千问手机版",
"TXYBA":"腾讯元宝手机版"
} }
def get_req_id(phone, begin, end): def get_req_id(phone, begin, end):
url = f"https://openapi.aidso.com/openapi/ywt/geoReqList?phone={phone}&begin={begin} 00:00:00&end={end} 23:59:59" url = f"https://openapi.aidso.com/openapi/ywt/geoReqList?phone={phone}&begin={begin} 00:00:00&end={end} 23:59:59"
...@@ -162,3 +368,176 @@ def qian_report(): ...@@ -162,3 +368,176 @@ def qian_report():
return success(result) return success(result)
except Exception as e: except Exception as e:
return fail('fail') return fail('fail')
@feishu_app.route("/feishu/static", methods=["POST"])
def zhou_report():
data = request.get_json() or {}
phone = data.get("phone")
begin = data.get("begin")
end = data.get("end")
brand_name = data.get("brand_name", [])
if not phone:
return fail("phone不能为空")
if not begin:
return fail("begin不能为空")
if not end:
return fail("end不能为空")
if not brand_name:
return fail("brand_name不能为空")
try:
req_list = get_req_id(phone, begin, end)
req_time_map = {}
req_ids = []
brand_id = 0
user_id = 0
for item in req_list:
if item.get('brand_name') == brand_name:
req_id = item.get("req_id")
user_id = item.get("user_id")
brand_id = item.get("brand_library_id")
created_at = item.get("created_at")
req_ids.append(req_id)
req_time_map[req_id] = created_at
result = []
platform_data = get_platforms(brand_id, user_id, begin, end)
geo_refer_rank_overview_vos = platform_data.get('geo_refer_rank_overview_vos')
brand_overview = platform_data.get('brand_overview')
for item in geo_refer_rank_overview_vos:
result.append({
"平台": plat_form_map.get(item.get("platform"), item.get("platform")),
"对话次数": item.get("ai_count"),
"提及率": item.get("refer_rate"),
"Top1提及率": item.get("top1_refer_rate"),
"Top3提及率": item.get("top3_refer_rate"),
"Top10提及率": item.get("top10_refer_rate"),
"平均提及排名": item.get("avg_rank"),
"提及好感度": item.get("sentiment_score"),
})
brand_overview_result = []
brand_overview_result.append({
'对话次数': brand_overview.get('ai_count'),
'提及对话次数': brand_overview.get('valid_rank_count'),
'提及率': brand_overview.get('refer_rate'),
'top1提及率': brand_overview.get('top1_refer_rate'),
'top3提及率': brand_overview.get('top3_refer_rate'),
'top10提及率': brand_overview.get('top10_refer_rate'),
'品牌提及次数': brand_overview.get('mention_count'),
'平均提及排名': brand_overview.get('avg_rank'),
'品牌提及好感度': brand_overview.get('sentiment_score'),
'品牌得分': brand_overview.get('brand_score')
})
# 概览数据
# 分平台数据
all_word = get_all_word_rank(brand_id, user_id, begin, end)
all_word_result = []
for all in all_word:
all_word_result.append({
"品牌提及次数": all.get('ref_count'),
"品牌名称": all.get("word"),
"品牌得分": all.get("score"),
"品牌提及率": all.get("rate"),
"平均提及排名": all.get("avg_rank")
})
# 全部品牌词数据
overview_result = []
sentiment_overview = get_sentiment_overview(brand_id, user_id, begin, end)
overview_result.append(
{
"提及品牌AI对话次数": sentiment_overview.get('sentiment_count'),
"品牌提及好感度": sentiment_overview.get('sentiment_score'),
"正面情感": sentiment_overview.get('positive_count'),
"中性情感": sentiment_overview.get('neutral_count'),
"负面情感": sentiment_overview.get('negative_count'),
"全部引用文章": sentiment_overview.get('article_count'),
"有品牌内容引用文章": sentiment_overview.get('has_brand_count'),
# todo 负面引用文章
"负面引用文章": sentiment_overview.get('negative_count')
}
)
platform_sentiment_result = []
platform_sentiment = get_platforms_sentiment(brand_id, user_id, begin, end)
for pla in platform_sentiment:
platform_sentiment_result.append({
"平台": plat_form_map.get(pla.get("platform"), pla.get("platform")),
"正面": round(pla.get('positive_count') / pla.get('sentiment_count'), 2),
"中性": round(pla.get('neutral_count') / pla.get('sentiment_count'), 2),
"负面": round(pla.get('negative_count') / pla.get('sentiment_count'), 2),
"提及品牌次数": pla.get('brand_words_count'),
"引用来源": pla.get('source_count'),
})
platform_list = ["DB", "DP", "TYQW", "TXYB", "BDAI", "DOUBA", "DPA", "DYAI", "KIMI", "WXYY"]
url_top_40 = get_url_top40(user_id, brand_id, begin, end, platform_list)
url_top_40_result = []
for url in url_top_40:
url_top_40_result.append({
"网站名称": url.get('site_name'),
"引用次数": url.get('log_count'),
"引用占比": url.get('quote_ratio_percent'),
})
site_category = get_site_category(brand_id, user_id, begin, end, platform_list)
site_category_result = []
for site in site_category:
site_category_result.append({
"站点类型": site.get('category'),
"站点数量": site.get('site_count'),
"引用文章数": site.get('resource_count'),
"引用次数": site.get('total_log_count'),
"引用率": site.get('quote_rate'),
})
quote_mention_word_cloud = get_quote_mention_word_cloud(brand_id, user_id, begin, end)
positive_top = quote_mention_word_cloud.get('positive_top')
negative_top = quote_mention_word_cloud.get('negative_top')
positive_top_result = []
for positive in positive_top:
positive_top_result.append({
"关键词": positive.get('word'),
"出现次数": positive.get('count'),
})
negative_top_result = []
for negative in negative_top:
negative_top_result.append({
"关键词": negative.get('word'),
"出现次数": negative.get('count'),
})
quto_statistics_result = []
quto_statistics = get_quto_statistics(brand_id, user_id, begin, end)
quto_statistics_result.append({
"引用文章数": quto_statistics.get('resource_count'),
"引用次数": quto_statistics.get('total_log_count'),
"引用网站": quto_statistics.get('site_count'),
})
refer_rate_heatmap = get_refer_rate_heatmap(brand_id, user_id, begin, end)
static_data = {
"brand_overview_result":brand_overview_result,
"result":result,
"all_word_result":all_word_result,
"overview_result":overview_result,
"platform_sentiment_result":platform_sentiment_result,
"url_top_40_result":url_top_40_result,
"site_category_result":site_category_result,
"positive_top_result":positive_top_result,
"negative_top_result":negative_top_result,
"quto_statistics_result":quto_statistics_result,
"refer_rate_heatmap":refer_rate_heatmap
}
return success(static_data)
except Exception as e:
return fail('fail')
\ No newline at end of file
import json import json
import traceback
from aidso_geo.models import spider_save_tos from aidso_geo.models import spider_save_tos
from aidso_geo.utils import robot_utils, tos_utils, bh_utils from aidso_geo.utils import robot_utils, tos_utils, bh_utils
...@@ -137,6 +138,7 @@ def doubao_process_original_data(file_path): ...@@ -137,6 +138,7 @@ def doubao_process_original_data(file_path):
suggestions,rich_media_block) suggestions,rich_media_block)
return (file_path, search_keyword, url_list, think_content, response_content, suggestions) return (file_path, search_keyword, url_list, think_content, response_content, suggestions)
except Exception as e: except Exception as e:
traceback.print_exc()
parts = file_path.split('/') parts = file_path.split('/')
platform = parts[2] platform = parts[2]
task_id = parts[1] task_id = parts[1]
...@@ -162,7 +164,7 @@ def doubao_process_original_data(file_path): ...@@ -162,7 +164,7 @@ def doubao_process_original_data(file_path):
if __name__ == '__main__': if __name__ == '__main__':
file_path = 'geo/21430906-2656-4ba4-b884-5f937745734c/DB/original.text' file_path = 'geo/50adc4fd-40de-4352-bb63-649207718036/DB/original.text'
doubao_process_original_data(file_path) doubao_process_original_data(file_path)
......
import json import json
import traceback
import aidso_geo.utils.bh_utils as bh_utils import aidso_geo.utils.bh_utils as bh_utils
import time import time
...@@ -1084,6 +1085,10 @@ def mark_source_mentioned(source_list, word_list): ...@@ -1084,6 +1085,10 @@ def mark_source_mentioned(source_list, word_list):
return result return result
def norm_source_id(v):
if v is None:
return ""
return str(v).strip()
def merge_mentioned(snippet_mention, quotes): def merge_mentioned(snippet_mention, quotes):
mentioned_map = {item["sourceId"]: item["hasBrand"] for item in snippet_mention} mentioned_map = {item["sourceId"]: item["hasBrand"] for item in snippet_mention}
...@@ -1093,9 +1098,11 @@ def merge_mentioned(snippet_mention, quotes): ...@@ -1093,9 +1098,11 @@ def merge_mentioned(snippet_mention, quotes):
def merge_sentiment(snippet_mention, quotes): def merge_sentiment(snippet_mention, quotes):
mentioned_map = {item["sourceId"]: item["sentiment"] for item in snippet_mention} mentioned_map = {norm_source_id(item.get("sourceId")): item.get("sentiment", "NEUTRAL")for item in snippet_mention}
for item in quotes: for item in quotes:
item["sentiment"] = mentioned_map.get(item["sourceId"], "NEUTRAL") sid = norm_source_id(item.get("sourceId"))
item["sentiment"] = mentioned_map.get(sid, "NEUTRAL")
return quotes return quotes
...@@ -1629,6 +1636,7 @@ def platform_process(data): ...@@ -1629,6 +1636,7 @@ def platform_process(data):
return True return True
except Exception as e: except Exception as e:
traceback.print_exc()
logger.exception( logger.exception(
f"{data['reqId']}--{data['platform']}--{data['prompt']}--PROCESS_FAIL" f"{data['reqId']}--{data['platform']}--{data['prompt']}--PROCESS_FAIL"
) )
...@@ -1838,21 +1846,25 @@ if __name__ == '__main__': ...@@ -1838,21 +1846,25 @@ if __name__ == '__main__':
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
# #
# begin = '2026-05-23' # begin = '2026-05-28'
# end = '2026-05-29' # end = '2026-06-04'
# req_list = get_req_id(15100000026,begin,end) # req_list = get_req_id(18900000004,begin,end)
# # b = "开云集团"
# req_ids = [] # req_ids = []
# for item in req_list: # for item in req_list:
# if item.get('brand_name') == b:
# req_id = item.get("req_id") # req_id = item.get("req_id")
# req_ids.append(req_id) # req_ids.append(req_id)
# req_id_sql = ",".join([f"'{req_id}'" for req_id in req_ids]) # req_id_sql = ",".join([f"'{req_id}'" for req_id in req_ids])
# print(req_id_sql)
# # print(len(req_ids))
query_sql = f"select * from geo_commit_task where reqId in ('e436cdd6-9342-4c67-b894-82bc8dc337a5')"
query_sql = f"select * from geo_commit_task where type = 'stream_batch' and status != 'SUCCESS'"
data_list = bh_utils.query_data(query_sql)
# print(len(data_list)) # print(len(data_list))
# #
# data_list = bh_utils.query_data(f"select * from geo_commit_task where status !='SUCCESS' and type = 'stream_batch' ") # data_list = bh_utils.query_data(f"select * from geo_commit_task where status ='ING' and type = 'stream_batch' ")
data_list = bh_utils.query_data(query_sql)
# print(data_list)
# # # # # #
# # # # # #
# # # # # # # # # #
......
...@@ -29,7 +29,6 @@ def yuanbao_process_original_data(file_path): ...@@ -29,7 +29,6 @@ def yuanbao_process_original_data(file_path):
# 提取并解析JSON数据 # 提取并解析JSON数据
data_str = i.split("data: ")[1] data_str = i.split("data: ")[1]
json_data = json.loads(data_str) json_data = json.loads(data_str)
except (IndexError, json.JSONDecodeError): except (IndexError, json.JSONDecodeError):
continue # 跳过格式错误的数据 continue # 跳过格式错误的数据
...@@ -75,6 +74,6 @@ def yuanbao_process_original_data(file_path): ...@@ -75,6 +74,6 @@ def yuanbao_process_original_data(file_path):
if __name__ == '__main__': if __name__ == '__main__':
# https://tcdn.aidso.com/geo/c7581554-435b-47ca-a2e5-d52bea763b8a/DOUBA/search_keyword.txt?secret=11049cbfb1c7018597a2085455505304520f0507080c0c4b514e09 # https://tcdn.aidso.com/geo/c7581554-435b-47ca-a2e5-d52bea763b8a/DOUBA/search_keyword.txt?secret=11049cbfb1c7018597a2085455505304520f0507080c0c4b514e09
file_path = 'geo/5582d220-f032-4095-ad39-1dbc33a536c3/TXYB/original.text' file_path = 'geo/b55be837-48a9-476a-8290-1339ea2ce3f9/TXYB/original.text'
yuanbao_process_original_data(file_path) yuanbao_process_original_data(file_path)
...@@ -40,7 +40,6 @@ def get_doubao_message(prop): ...@@ -40,7 +40,6 @@ def get_doubao_message(prop):
} }
response = requests.request("POST", url, headers=headers, data=payload) response = requests.request("POST", url, headers=headers, data=payload)
response_json = response.json() response_json = response.json()
text = "" text = ""
quto = "" quto = ""
...@@ -173,14 +172,6 @@ def get_parse_sse_result(platform, task_id): ...@@ -173,14 +172,6 @@ def get_parse_sse_result(platform, task_id):
# 元宝 # 元宝
# 文心一言 # 文心一言
if __name__ == '__main__': if __name__ == '__main__':
result = get_qianwewn_message("dso是什么")
print(result)
# result = [{'id': 'rs_02176302229863300000000000000000000ffffac15dd3712c724', 'type': 'reasoning', 'summary': [{'type': 'summary_text', 'text': '我现在需要回答用户的问题“dso是什么”。首先,我得确定DSO这个缩写可能代表的含义。DSO在不同领域有不同的意思,比如在金融领域,DSO是Days Sales Outstanding的缩写,指的是应收账款周转天数;在电子工程里,可能指Digital Storage Oscilloscope(数字存储示波器);还有可能是其他领域的术语,比如组织名称、技术名词等。\n\n用户的问题比较简短,没有上下文,所以我需要考虑多个可能性。不过,为了准确回答,最好通过搜索工具来确认最常见的含义以及是否有最新的相关信息。比如,是否有新的机构、技术或者事件使用DSO这个缩写?\n\n接下来,我需要选择合适的搜索工具。根据提供的工具列表,web_search可以选择多个source_types。考虑到DSO可能涉及多个领域,应该选择search_engine和douyin_baike这两个源。search_engine可以提供全网信息,而douyin_baike可能有更专业的百科解释。\n\n然后,确定搜索的关键词。直接用“DSO是什么”作为查询词应该可以覆盖主要含义。可能需要同时搜索多个关键词,但这里一个关键词应该足够,因为问题比较直接。\n\n检查参数是否符合要求:source_types需要至少一个,这里选search_engine和douyin_baike;queries是数组,包含一个查询词。确认无误后,生成工具调用的JSON结构。'}], 'status': 'completed'}, {'type': 'web_search_call', 'action': {'query': 'dso是什么', 'type': 'search'}, 'status': 'completed', 'id': 'ws_02176302230525400000000000000000000ffffac15dd37f6f16b'}, {'id': 'rs_02176302230724100000000000000000000ffffac15dd3748c557', 'type': 'reasoning', 'summary': [{'type': 'summary_text', 'text': '\n用户问"dso是什么",我需要先看搜索结果里的信息。搜索结果里有几个不同的解释:\n\n首先看摘要1,Digital Storage Oscilloscope(数字存储示波器),这个是比较常见的电子设备,摘要1详细讲了原理和应用,还有摘要5也是讲这个的,来自Tektronix,权威。然后摘要2提到Device Software Optimization(设备软件优化),是软件工具类的;摘要3是Direct Sparse Odometry,计算机视觉里的视觉里程计方法;摘要4是Days Sales Outstanding,企业财务里的应收账款平均收款天数。\n\n所以DSO有多个含义,得把这些不同领域的解释都列出来,每个含义说明清楚对应的领域和主要内容。需要确认每个解释的准确性,比如财务那个摘要4是2025年的,比较新;视觉那个摘要3是2023年的论文解读;示波器的摘要1是2024年的,都比较可靠。不需要再搜索了,因为已经覆盖了几个主要领域的含义,信息足够回答用户的问题。'}], 'status': 'completed'}, {'type': 'message', 'role': 'assistant', 'content': [{'type': 'output_text', 'text': 'DSO是一个多义词,在不同领域有不同含义,以下是主要解释:\n\n### 1. **数字存储示波器(Digital Storage Oscilloscope)** \n电子工程领域的基础测量仪器,通过数字化方式采集、存储和分析电信号波形。 \n- **核心功能**: \n - 捕捉单次/非周期信号,支持波形存储、回放与对比; \n - 高精度测量频率、幅值、上升时间等参数; \n - 可通过接口将数据传输至计算机进行深入分析; \n- **应用场景**:电子设备研发、故障诊断、自动化测试等。 \n\n### 2. **应收账款平均收款天数(Days Sales Outstanding)** \n企业财务管理指标,反映应收账款回收效率。 \n- **计算公式**:`DSO = 应收账款余额 ÷ 年销售额 × 365天`; \n- **意义**:数值越低表示回款速度越快,现金流健康度越高;数值过高可能导致资金链压力; \n- **优化方式**:加强客户信用评估、制定催收政策、使用信息化管理系统等。 \n\n### 3. **直接稀疏里程计(Direct Sparse Odometry)** \n计算机视觉领域的视觉里程计算法(SLAM技术分支)。 \n- **核心特点**: \n - 采用稀疏直接法估计相机运动,无需提取特征点; \n - 速度快(据称可达传统特征点法5倍),精度较高但存在累计误差; \n - 仅实现单目视觉里程计,无回环检测功能; \n- **应用场景**:机器人导航、自动驾驶环境感知等。 \n\n### 4. **设备软件优化(Device Software Optimization)** \n软件工程领域的工具/方法集,用于提升嵌入式设备软件性能。 \n- **目标**:降低开发成本、提高软件可靠性与运行效率; \n- **应用场景**:智能硬件、工业设备、消费电子等嵌入式系统开发。 \n\n需根据具体上下文判断DSO的含义。', 'annotations': [{'type': 'url_citation', 'title': '数字存储示波器的原理和应用', 'url': 'https://m.sohu.com/a/843397558_121970079/', 'logo_url': 'https://p11-volcsearch-sign.byteimg.com/isp-i18n-media/img/6b1d3a6f49304d84d8268210e144399e~tplv-obj.jpeg?lk3s=7acb411c&scene=volc_search&x-expires=1825138266&x-signature=PTxYC7LXmtjxkZRbRv4GCMuDCdU%3D', 'site_name': '搜索引擎-手机搜狐网', 'publish_time': '2024年12月30日 14:16:00(CST) 星期一', 'summary': '数字存储示波器(Digital Storage Oscilloscope,简称DSO)是一种采用数字电路进行模/数转换,并通过存储器实现对触发前信号进行记忆的一种具备存储功能的数字化设备。以下是对其原理及应用的详细介绍:\n数字存储示波器\n一、原理 \n信号采集与数字化: \n当信号进入数字存储示波器后,示波器会按一定的时间间隔对信号电压进行采样。\n采样得到的模拟信号经过模/数变换器(ADC)进行数字化处理,生成代表每一个采样电压的二进制字。 \n信号存储与处理: \n数字化后的信号被存储在示波器的存储器(如RAM)中。\n示波器内部的微处理器可以对存储的信号进行各种处理,如测量、分析、显示等。 \n展开剩余 61 % \n信号显示: \n当需要观察存储的信号时,微处理器会从存储器中按原顺序取出数字信号。\n这些数字信号经过数/模转换器(D/A)转换回模拟信号,并经过放大后送到示波器的阴极射线管(CRT)或其他显示设备上显示出来。 \n触发机制: \n示波器通常具有触发功能,可以根据设定的触发条件(如信号电压达到某值并处于上升沿)开始采集和显示信号。\n触发机制确保了示波器能够稳定地显示信号波形。\n二、应用 \n波形观测与比较: \n数字存储示波器可以观测和比较单次过程和非周期现象、低频和慢速信号,以及不同时间不同地点观测到的信号。\n它还可以同时显示不同时间或相同时间发生的几个波形,便于对波形进行仔细分析和研究。 \n数据存储与传输: \n由于数字存储示波器以数字形式存储信号波形,因此可以长时间地保存信号数据。\n这些数据可以通过标准接口(如GPIB接口)传输到计算机或其他外部设备上进行进一步的分析和处理。 \n测量与分析: \n数字存储示波器具有高精度的测量功能,可以测量信号的频率、幅值、上升时间等参数。\n它还可以对存储的信号进行各种数字处理分析,如平均选加、信号的相关处理、频谱分析、能谱分析和FFT分析等。 \n自动化测试: \n数字存储示波器通常具有程控和遥控能力,可以通过编程实现自动化测试。\n这使得它在生产线测试、自动测试系统等领域具有广泛的应用前景。\n综上所述,数字存储示波器以其独特的原理和广泛的应用领域,在电子测量领域发挥着重要作用。 \n发布于:广东省 \n'}, {'type': 'url_citation', 'title': 'DSO市场地位抬头', 'url': 'https://www.cnblogs.com/safeking/archive/2005/07/12/191071.html', 'logo_url': 'https://p11-volcsearch-sign.byteimg.com/isp-i18n-media/image/8b678b679949fd7841e473fe5e088a50~tplv-obj.jpeg?lk3s=7acb411c&scene=volc_search&x-expires=1825138266&x-signature=hXL2uwqkIwhGyZ0sIQVw04IneGU%3D', 'site_name': '搜索引擎-博客园', 'publish_time': '2005年07月12日 08:30:00(CST) 星期二', 'summary': 'DSO市场地位抬头作为一种新的软件门类,DSO(Device software optimization,设备软件优化)已经得到业界的逐渐认可,并且将会对全球电子制造业带来深远的影响。大到舰船、飞机和宇宙飞船,小到我们手中的数码相机和MP3播放器,任何需要软件来进行控制的电子设备都将因为这个新概念的诞生而变得更加聪明、可靠、廉价。那么,什么是DSO?它与以前的嵌入式软件(Embedded Software)有何联系与区别?它将以怎样的方式来影响电子制造业?电子制造厂商应该怎样迎接DSO时代的来临?就让我们一起来拨开这一层层迷雾。DSO——来得正是时候DSO(Device Software Optimization,设备软件优化)是一套帮助电子制造厂商,使其产品中的软件更加快速、可靠的工具和方法,同时可以让这些软件的开发成本大幅度降低,并且通过提高软件可靠性而降低产品的维护成本。与所有的产业都一样,电子设备制造厂商永远都面临着降低成本的压力。厂商们总是希望自己的产品更加可靠、更加智能化。不仅如此,最重要的是,有越来越多的设备已经把网络互联能力作为一种必须的功能,以便与其他的设备交换信息,或者在更加复杂的网络环境中进行管理、控制与协同。任何设备的信息共享与网络控制功能都必须通过更加复杂的软件来实现。'}, {'type': 'url_citation', 'title': 'DSO详解-Direct Sparse Odometry论文解读', 'url': 'https://blog.csdn.net/weixin_41803874/article/details/84197226', 'logo_url': 'https://p26-volcsearch-sign.byteimg.com/isp-i18n-media/img/a1684c00ee5f4a62c7c1047d6d51b665~tplv-obj.jpeg?lk3s=7acb411c&scene=volc_search&x-expires=1825138266&x-signature=b0jiHNap9b2kl%2B5izFQ4AOYH9FE%3D', 'site_name': '搜索引擎-CSDN博客', 'publish_time': '2023年05月24日 11:00:30(CST) 星期三', 'summary': 'DSO详解-Direct Sparse Odometry论文解读 转载\n元学习论文总结||小样本学习论文总结\n2017-2019年计算机视觉顶会文章收录 AAAI2017-2019 CVPR2017-2019 ECCV2018 ICCV2017-2019 ICLR2017-2019 NIPS2017-2019\nDSO(Direct Sparse Odometry),是慕尼黑工业大学(Technical University of Munich, TUM)计算机视觉实验室的雅各布.恩格尔(Jakob Engel)博士,于2016年发布的一个视觉里程计方法(期刊论文见[1],实验室主页见Computer Vision Group)。在SLAM领域,DSO属于稀疏直接法,据论文称能达到传统特征点法的五倍速度(需要降低图像分辨率),并保持同等或更高精度,代码见:JakobEngel/dso。然而,由于某些历史和个人的原因,DSO的代码清晰度和可读性,明显弱于其他SLAM方案如ORB、SVO、okvis等,使得研究人员很难以它为基础,展开后续的研究工作。因此,本文希望从理论和实现层面解读DSO,尝试为其他对DSO感兴趣的研究人员提供一些有益的思路和观点。\n注:\n为了读懂本文,我们假定读者已具有视觉SLAM的基本知识,否则,请先阅读相关材料。另外,如果读过DSO论文或代码,可能对本文有更好的理解。\n由于知乎平台分辨率限制,插图可能不够清晰。如果能图像质量有更高要求,请联系作者:gao.xiang.thu at gmail dot com.\n由于本文较长,我会花几次时间进行更新,应读者要求先发布草稿版。\n以下是本文的提纲:\n提纲\n概述\n流程框架\n滑动窗口\n光度标定\n评述\n资料与参考文献\n\xa0\n概述\nDSO属于稀疏直接法的视觉里程计。它不是完整的SLAM,因为它不包含回环检测、地图复用的功能。因此,它不可避免地会出现累计误差,尽管很小,但不能消除。DSO目前开源了单目实现,双目DSO的论文已被ICCV接收,但目前未知是否开源。\nDSO是少数使用纯直接法(Fully direct)计算视觉里程计的系统之一。相比之下,SVO[2]属于半直接法,仅在前端的Sparse model-based Image Alignment部分使用了直接法,之后的位姿估计、bundle adjustment'}, {'type': 'url_citation', 'title': 'dso是什么意思', 'url': 'https://www.580dns.com/knowledgebaseview?id=21797', 'logo_url': 'https://p26-volcsearch-sign.byteimg.com/isp-i18n-media/img/d76ba6af720a8c8489d3c62a7cf45707~tplv-obj.jpeg?lk3s=7acb411c&scene=volc_search&x-expires=1825138266&x-signature=gS1dWCQF8X3Gl8mwNCQsx7PJT48%3D', 'site_name': '搜索引擎-达州创梦网络', 'publish_time': '2025年02月19日 00:00:00(CST) 星期三', 'summary': 'dso是什么意思\nDSO是衡量企业应收账款周转速度的指标,反映公司收款效率和财务状况,计算公式为应收账款/年销售额/销售天数,对现金流和资金周转至关重要。优化DSO需制定严格管理政策、强化销售团队培训、采用信息管理系统等。\nDSO是什么意思\n一、DSO的概述\nDSO,全称Days Sales Outstanding,中文可以译为“应收账款平均收款天数”。它是一个衡量企业应收账款周转速度的重要指标,通常用来反映公司对客户的收款效率和企业的财务状况。DSO的长短与企业的财务管理水平和资金使用效率息息相关。\n二、DSO的计算方式\nDSO的计算通常通过总赊销净额与平均应收款的应收账款回收周期(平均)进行比较。一般来说,计算公式如下:\nDSO = 应收账款 / 年销售额/销售天数\n这个公式可以得出企业平均需要多少天才能将应收账款收回。\n三、DSO的重要性\nDSO对于企业来说非常重要,因为它直接关系到企业的现金流和资金周转。一个较高的DSO值可能意味着企业的应收账款回收周期较长,这可能会对企业的资金链造成压力。相反,一个较低的DSO值则表明企业能够快速地回收账款,有更好的现金流管理和使用效率。\n四、如何优化DSO\n对于企业来说,优化DSO非常重要。首先,需要制定严格的应收账款管理政策,包括制定合理的赊销政策、加强客户信用评估等。其次,要强化对销售团队的培训和管理,提高他们的账款催收能力和责任心。同时,需要采用有效的技术和手段,比如现代化的信息管理系统,来更好地追踪和监控应收账款的状态和进度。\n此外,要确保企业在商业竞争中能够持续保持竞争力,必须加强与客户的沟通和合作,建立长期稳定的合作关系。这样不仅可以提高客户的满意度和忠诚度,还可以通过与客户共同协商和合作来优化DSO。\n总之,DSO是衡量企业财务管理水平的重要指标之一。通过了解其含义、计算方式以及重要性,企业可以更好地管理其应收账款,优化资金使用效率,提高企业的竞争力和盈利能力。\n标签:\nDSO\n应收账款\n平均收款天数\n计算方式\n财务管理\n'}, {'type': 'url_citation', 'title': 'Digital Storage Oscilloscopes', 'url': 'https://www.tek.com/en/oscilloscope/digital-storage-oscilloscope-dso', 'logo_url': 'https://p26-volcsearch-sign.byteimg.com/isp-i18n-media/image/3f6bf1aefb48a96480eaae850e4f3896~tplv-obj.jpeg?lk3s=7acb411c&scene=volc_search&x-expires=1825138266&x-signature=qEYiJrrbs%2FP00iExeJmYgLIElew%3D', 'site_name': '搜索引擎-Tektronix', 'publish_time': '1970年01月01日 08:00:00(CST) 星期四', 'summary': 'Digital Storage Oscilloscopes\nDigital Storage Oscilloscopes (DSO)\nA digital storage oscilloscope (DSO) is a fundamental tool used in electrical engineering and electronics design, offering a digital approach to signal analysis that surpasses the capabilities of traditional analog oscilloscopes. With a DSO, professionals and enthusiasts alike can capture, store, and analyze complex electronic signals, facilitating a deeper understanding of electrical phenomena.\nWhat is a DSO?\nA DSO is an instrument that captures and stores digital representations of electrical signals. Unlike its analog predecessors that relied on phosphor to display signals, DSOs use a digital screen to render waveform data, enabling a more versatile and detailed examination of electrical signals. This also allows more specialized analysis tools to be utilized on the instrument.\nKey Features of DSOs:\nPermanent Signal Storage : Waveforms captured by a DSO are stored in digital form, allowing for easy retrieval, analysis'}]}], 'status': 'completed', 'id': 'msg_02176302231280100000000000000000000ffffac15dd375253d2'}]
# for i in result_list:
# if i.get('type') == 'message':
# for j in i.get('content'):
# print(j.get('text'))
# print(j.get('annotations'))
text,quto = get_doubao_message("GEO服务商推荐")
print(quto)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment