Python+Selenium+Pytest+Allure PO模式UI自动化框架
一、框架结构
- allure-report:测试报告
- base:定位元素封装
- data:数据
- log:日志文件
- page:页面封装文件夹
- report:缓存报告
- testcases:测试用例层
- utils:工具类
- run.py:执行文件
二、封装类
base.py
import datetime
import timefrom selenium.webdriver import Keys, ActionChains
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from utils.log_util import loggerclass BasePage:def __init__(self, driver):self.driver = driverself.driver.maximize_window()self.driver.implicitly_wait(10) # 隐式等待self.wait = WebDriverWait(self.driver, 10) # 显示等待self.actions = ActionChains(self.driver) # 鼠标动作链初始化# 这是基础的find_element封装# def find_element(self, locator):# logger.info(f"当前定位{locator}")# return self.driver.find_element(*locator)def find_element(self, locator, condition='visibility', retry=1):""":param locator: 元素定位信息:param condition: 默认是visibility:param retry: 重试次数,默认是1,重试一次:return:"""for time in range(retry + 1):try:logger.info(f"定位元素{locator}")if condition == 'visibility':node = self.wait.until(EC.visibility_of_element_located(locator))else:node = self.wait.until(EC.presence_of_element_located(locator))return nodeexcept Exception as e:error_info = f"{locator}定位失败,错误信息{e}"logger.error(error_info)if time < retry:logger.info(f"正在重新定位,当前重试次数:{time + 1}")else:raise Exception(error_info)def find_elements(self, locator, retry=1):"""返回列表节点:param locator: 元素定位信息:param retry: 重试次数,默认是1,重试一次:return:"""for time in range(retry + 1):try:logger.info(f"定位元素{locator}")node = self.wait.until(lambda x: x.find_elements(*locator))return nodeexcept Exception as e:error_info = f"{locator}定位失败,错误信息{e}"logger.error(error_info)if time < retry:logger.info(f"正在重新定位,当前重试次数:{time + 1}")else:raise Exception(error_info)def send_keys(self, locator, value, enter=False):"""封装输入内容函数:param locator: 元素定位信息:param value: 输入项的内容:return:"""# 1. 先定位元素node = self.find_element(locator)# 2. 清空输入框node.clear()# 3. 输入内容node.send_keys(value)logger.info(f"输入内容为:{value}")if enter:# 调用键盘的回车键node.send_keys(Keys.ENTER)logger.info("点击回车键")def click(self, locator):"""定位元素并点击:param locator: 元素定位信息:return:"""# 1. 先定位元素node = self.find_element(locator)# 2. 点击node.click()logger.info("点击按钮")def get_url(self, url=''):"""请求url:param url: 网址:return:"""self.driver.get(url)logger.info(f"打开网址{url}")def close_driver(self):"""关闭浏览器:return:"""logger.info("关闭浏览器")self.driver.close()def quit_driver(self):"""退出浏览器:return:"""logger.info("退出浏览器")self.driver.quit()def refresh(self):"""刷新浏览器:return:"""self.driver.refresh()logger.info("刷新浏览器")def switch_to_window(self, to_parent_window=False):"""切换窗口:param to_parent_window: 是否回到主窗口:return:"""total = self.driver.window_handlesif to_parent_window:# 切换到主窗口self.driver.switch_to.window(total[0])else:# 获取当前窗口current_window = self.driver.current_window_handlefor window in total:if window != current_window:logger.info("切换窗口")self.driver.switch_to.window(window)def get_title(self):"""获取网页title:return:"""return self.driver.titledef get_current_url(self):"""获取当前的URL:return:"""return self.driver.current_urldef get_page_source(self):"""获取网页源代码:return:"""return self.driver.page_sourcedef get_text(self, locator):"""获取元素的文本内容:param locator: 元素定位信息:return:"""ele = self.find_element(locator)text = ele.textif text == "":text = ele.accessible_namelogger.info(f"元素{locator}的text为{text}")return textdef move_to_element(self, locator):"""鼠标移动到指定位置:param locator: 指定位置:return:"""ele = self.find_element(locator)self.actions.move_to_element(ele).perform()logger.info(f"鼠标移动到{locator}位置")def drag_and_drop(self, locator_start, locator_end):"""鼠标拖动元素到另一个元素:param locator_start: 元素开始位置:param locator_end: 元素结束位置:return:"""start = self.find_element(locator_start)end = self.find_element(locator_end)self.actions.drag_and_drop(start, end).perform()logger.info(f"鼠标从{locator_start}拖动到{locator_end}")def drag_and_drop_by_offset(self, locator, x, y):"""拖动一段距离:param locator: 拖动的元素:param x: x距离:param y: y距离:return:"""ele = self.find_element(locator)self.actions.drag_and_drop_by_offset(ele, x, y)logger.info("鼠标拖动一段距离")def select_by_index(self, locator, index):"""根据下标获取select:param locator: 元素定位信息:param index: 下标,从0开始:return:"""ele = self.find_element(locator)select = Select(ele)select.select_by_index(index)logger.info(f"根据下表{index}获取select")def select_by_value(self, locator, value):"""根据value值获取select:param locator: 元素定位信息:param value: value值:return:"""ele = self.find_element(locator)select = Select(ele)select.select_by_value(value)logger.info(f"根据下表{value}获取select")def select_by_visible_text(self, locator, visible_text):"""根据visible_text值获取select:param locator: 元素定位信息:param visible_text: visible_text值:return:"""ele = self.find_element(locator)select = Select(ele)select.select_by_visible_text(visible_text)logger.info(f"根据下表{visible_text}获取select")# 等待元素存在def wait_ele_presence(self, locator, center=True):""" 知识点解析:#scrollIntoView:# 如果为true,元素的顶端将和其所在滚动区的可视区域的顶端对齐。# 如果为false,元素的底端将和其所在滚动区的可视区域的底端对齐。#scrollIntoViewIfNeeded:#如果为true,则元素将在其所在滚动区的可视区域中居中对其。# 如果为false,则元素将与其所在滚动区的可视区域最近的边缘对齐。 根据可见区域最靠近元素的哪个边缘,# 元素的顶部将与可见区域的顶部边缘对准,或者元素的底部边缘将与可见区域的底部边缘对准。"""try:start = datetime.datetime.now()ele = self.wait.until(EC.presence_of_element_located(locator))end = datetime.datetime.now()logger.info("元素{}已存在,等待{}秒".format(locator, (end - start).seconds))self.driver.execute_script("arguments[0].scrollIntoViewIfNeeded(arguments[1]);", ele, center)return eleexcept Exception:logger.error("元素不存在-{}".format(locator))raisedef execute_js(self, element):self.driver.execute_script("arguments[0].click();", element)def switch_to_frame(self, index=0, to_parent_frame=False, to_default_frame=False):"""切换到不同的frame框架:param index: expect by frame index value or id or name or element:param to_parent_frame: 是否切换到上一个frame,默认False:param to_default_frame: 是否切换到最上层的frame,默认False:return:"""if to_parent_frame:self.driver.switch_to.parent_frame()elif to_default_frame:self.driver.switch_to.default_content()else:self.driver.switch_to.frame(index)logger.info(f'切换frame,to:{index}')def popup_window_operation(self, action='yes', send_info='', get_window_info=False):"""弹窗操作:param action: 要执行的动作,yes or no:param send_info: 在弹窗的文本框内输入信息:param get_window_info: 获取弹窗的文本信息:return:"""if self.wait.until(EC.alert_is_present()):if send_info:logger.info(f'在弹窗上输入信息:{send_info}')self.driver.switch_to.alert.send_keys(send_info)if get_window_info:popup_info = self.driver.switch_to.alert.textlogger.info(f'获取弹窗的文本信息:{popup_info}')return popup_infoif action == 'yes':logger.info('在弹窗上点击确认')self.driver.switch_to.alert.accept() # 点击确认else:logger.info('在弹窗上点击取消')self.driver.switch_to.alert.dismiss() # 点击取消def page_scrolling(self, go_to_bottom=False, rolling_distance=(0, 1000)):"""页面滚动,如果没有滚动效果,添加延时(页面需要全部加载完毕才能滚动):param bool go_to_bottom: 是否直接滚动到当前页面的最底部,默认False:param tuple rolling_distance: 滚动距离,默认是向下滚动1000像素:return:"""if go_to_bottom:js = "window.scrollTo(0, document.body.scrollHeight)"else:js = "window.scrollBy({}, {})".format(rolling_distance[0], rolling_distance[1])self.driver.execute_script(js)logger.debug(f'页面滚动完毕')def back(self):"""网页后退"""self.driver.back()logger.debug('网页后退')def forward(self):"""网页前进"""self.driver.forward()logger.debug('网页前进')# 获取元素的属性def get_ele_attribute(self, locator, name, center=True):ele = self.wait_ele_presence(locator, center)try:value = ele.get_attribute(name)logger.info("元素{}的{}属性-{}".format(locator, name, value))return valueexcept:logger.error("元素获取属性{}失败-{}".format(name, locator))raise
page 文件
user_page.py示例
import allure
from selenium.webdriver.common.by import By
from base.base_page import BasePage
from testcases.user_center.conftest import delete_user, delete_code
from utils.assert_util import assert_compare"""
后台登录商户余额审核
"""
class UserPage(BasePage):# 选择城市login_city = (By.XPATH, '//*[@id="app"]/div/div[2]/div/div/div[2]/button/span')# 选择全部取消click_all = (By.XPATH, '//*[@id="app"]/div/div[2]/div/div/div[6]/div/div[2]/form/div/div/div[2]/label/span[1]/span')# 选择自营深圳click_sz = (By.XPATH, '//*[@id="app"]/div/div[2]/div/div/div[6]/div/div[2]/form/div/div/div[3]/div[1]/div/div/div/label[7]/span[1]/span')# 点击确认click_confir= (By.XPATH, '//*[@id="app"]/div/div[2]/div/div/div[6]/div/div[3]/div/button[2]/span')# 用户列表-手机号搜索phone_serch = (By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[1]/div/div[1]/form/div[2]/div/div/input')def login(self):self.get_url("https://XXXX/?#/login")self.send_keys(self.login_account, "admin")self.send_keys(self.login_password, "123456")self.send_keys(self.login_code, 1)self.click(self.login_btn)
testcese 文件
test_user.py示例
import time
import allure
import pytest
from page.user_page import UserPage
# from testcases.user_center.conftest import delete_user, delete_code
from utils.assert_util import assert_compare
# from utils.mysql_util import db
from utils.read import read_yaml@allure.epic("财务余额调控")
@allure.feature("余额调控")
@pytest.mark.run(order=1)
class TestUser:@allure.title("用户登录")@pytest.mark.parametrize('data', read_yaml()['user_login'])def test_user_login(self, driver_project, data):username, password,code = str(data['username']), str(data['password']),str(data['code'])page = UserPage(driver_project)page.get_url('https://XXXXX/?#/login')# page.refresh()page.send_keys(page.login_account, username)page.send_keys(page.login_password, password)page.send_keys(page.login_code, code)page.click(page.login_btn)time.sleep(3)
- conftest.py文件
import allure
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from utils.get_filepath import get_screen_shot_path
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import WebDriverException
options = Options()
options.binary_location = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
service = Service(r'C:\Program Files\Google\Chrome\Application\chromedriver.exe')
options.add_argument("--headless")
options.add_argument("--disable-dev-shm-usage")try:driver = webdriver.Chrome(options=options)
except WebDriverException as e:print("完整错误信息:", e.msg)with open("error.log", "w") as f:f.write(str(e))@pytest.fixture(scope="session")
def driver_project():global driverdriver = webdriver.Chrome()driver.maximize_window()driver.get("https://XXXXX/?#/login")# print(driver.page_source)print("打开浏览器")yield driverprint("关闭浏览器")driver.close()driver.quit()# 钩子函数,结果
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):""":param item: 代表测试函数或方法,包含测试相关的信心,比如名称,位置,标记:param call: 包含测试函数执行的详细信息,比如结果,执行时间:return:when = setup:前置when = call:执行测试用例when = teardown:后置"""print("=========================")# 获取钩子函数的结果out = yield# 获取测试报告report = out.get_result()print(f"测试报告:{report}")print(f"步骤:{report.when}")print(f"nodeid:{report.nodeid}")print(f"运行结果:{report.outcome}")# 失败测试用例截图if report.when == 'call' and report.failed:# 保存到本地driver.save_screenshot(get_screen_shot_path())# 截图,get_screenshot_as_png二进制数据# 使用allure.attach将二进制数据附加到allure报告中allure.attach(driver.get_screenshot_as_png(), "用例执行失败截图", allure.attachment_type.PNG)
utils 文件夹
- assert_util.py
from utils.log_util import loggerdef assert_compare(expect, compare, actual):""":param expect: 预期结果:param compare: 断言方式:param actual: 实际结果:return:"""logger.info(f"预期结果:{expect} {compare} {actual}")try:if compare == "==":assert expect == actualelif compare == "!=":assert expect != actualelif compare == ">":assert expect > actualelif compare == "<":assert expect < actualelif compare == "in":assert expect in actualelse:try:raise NameError(f"{compare} 断言方式错误,请填写正确")except Exception as e:logger.error(e)raiselogger.info("断言成功")except AssertionError as e:logger.error(f"断言失败{e}")raise
- get_filepath.py
import os
import timedef get_report_path():path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "allure-report/export",'prometheusData.txt')return pathdef get_screen_shot_path():file_name = "截图{}.png".format(time.strftime("%Y-%m-%d_%H-%M-%S"))path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "file", file_name)return pathdef get_logo_path():path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "file", "logo.jpg")return pathdef download_file_path():path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "file")return pathdef get_yaml_path():path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "data", "data.yaml")return pathdef get_ini_path():path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "config", "settings.ini")return pathdef get_log_path():path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "log")return pathif __name__ == '__main__':print(get_report_path())
- log_util.py
import logging
import os
import timefrom utils.get_filepath import get_log_pathlog_path = get_log_path()if not os.path.exists(log_path):os.mkdir(log_path)class Logger:def __init__(self):# 定义日志位置和文件名self.logname = os.path.join(log_path, "{}.log".format(time.strftime("%Y-%m-%d")))# 定义一个日志容器self.logger = logging.getLogger("log")# 设置日志打印的级别self.logger.setLevel(logging.DEBUG)# 创建日志输入的格式self.formater = logging.Formatter('[%(asctime)s][%(filename)s %(lineno)d][%(levelname)s]: %(message)s')# 创建日志处理器,用来存放日志文件self.filelogger = logging.FileHandler(self.logname, mode='a', encoding="UTF-8")# 文件存放日志级别self.filelogger.setLevel(logging.DEBUG)# 文件存放日志格式self.filelogger.setFormatter(self.formater)# 创建日志处理器,在控制台打印self.console = logging.StreamHandler()# 设置控制台打印日志界别self.console.setLevel(logging.DEBUG)# 控制台打印日志格式self.console.setFormatter(self.formater)# 将日志输出渠道添加到日志收集器中self.logger.addHandler(self.filelogger)self.logger.addHandler(self.console)logger = Logger().loggerif __name__ == '__main__':logger.debug("我打印DEBUG日志")logger.info("我打印INFO日志")logger.warning("我打印WARNING日志")logger.error("我打印ERROR日志")
- read.py
import configparserimport yamlfrom utils.get_filepath import get_yaml_path, get_ini_pathpath = get_yaml_path()
ini_path = get_ini_path()def read_yaml():with open(path, encoding="utf8") as f:data = yaml.safe_load(f)return datadef read_ini():config = configparser.ConfigParser()config.read(ini_path, encoding='utf8')return configif __name__ == '__main__':print(read_yaml())# print(read_ini()['mysql']['HOST'])
- pytest.ini
[pytest]
;使用testpaths指定测试用例运行目录或者运行文件
testpaths = testcases/official_website testcases/user_center testcases/reward_punish testcases/order_center
;mark标记
markers=pro:protest:testp1:p1addopts: -vs --alluredir ./report --clean-alluredir
- run.py
import pytestimport osif __name__ == '__main__':# 1.执行测试用例pytest.main()os.system("copy environment.properties .\\report")# 2.生成报告os.system("allure generate report -o allure-report --clean")# 3.打开报告os.system("allure open allure-report")
三、测试报告
- 测试报告展示如图
- 报告详情展示
相关文章:
Python+Selenium+Pytest+Allure PO模式UI自动化框架
一、框架结构 allure-report:测试报告base:定位元素封装data:数据log:日志文件page:页面封装文件夹report:缓存报告testcases:测试用例层utils:工具类run.py:执行文件 二…...
【C语言操作符详解(一)】--进制转换,原反补码,移位操作符,位操作符,逗号表达式,下标访问及函数调用操作符
目录 一.操作符的分类 二.二进制和进制转换 2.1--2进制转10进制 编辑 2.1.1--10进制转2进制数字 2.2--2进制转8进制和16进制 2.2.1--2进制转8进制 2.2.2--2进制转16进制 三.原码,反码,补码 四.移位操作符 4.1--左移操作符 4.2--右移操作符…...
回顾|Apache Cloudberry™ (Incubating) Meetup·2025 杭州站
2025 年 4 月 19 日,由酷克数据与中启乘数联合举办的 Apache Cloudberry™ (Incubating) Meetup 杭州站在浙江省杭州市滨江区滨江会展中心成功举办。本次活动邀请了 Cloudberry PPMC 团队成员、活跃内核贡献者以及中兴 EBASE-A、阿里云 ADB-PG、网易、中启乘数等多…...
使用 Autofac 实现依赖注入
前言:接上一篇文章,有了微软官方的依赖注入组件Microsoft.Extensions.DependencyInjection, 那么今天介绍一个新的开源的依赖注入组件Autofac 一、二者的差异Autofac和微软官方的依赖注入组件(Microsoft.Extensions.DependencyIn…...
HTTP:十二.HTTPS
HTTPS 概述 超文本传输安全协议(英语:HyperText Transfer Protocol Secure,缩写:HTTPS;常称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,利用TLS加密数据包。 HTTPS的主要目的是提供对网站服务器…...
《代码整洁之道》第12章 迭进 - 笔记
好的设计是如何形成的? 章节核心: 好的软件设计不是完全靠前期庞大的设计方案来完成的,而更多地是在持续的编码、测试和重构过程中,“涌现”或“演进”出来的。 设计不是一次性的前期活动 大白话: 作者认为&#x…...
数字巴别塔:全栈多模态开发框架如何用自然语言重构软件生产关系?
一、自然语言编程的范式革命 1. 从代码行数到语义密度 开发效率对比(某金融 SaaS 案例): 开发方式代码量(行)开发时间(天)维护成本($/年)传统 React5,2004512,000低代码…...
【C语言极简自学笔记】C 语言数组详解:一维数组与二维数组
在 C 语言中,数组是一种非常重要的数据结构,它可以将多个相同类型的元素组织在一起,以便于我们进行批量处理和操作。本文将详细介绍 C 语言中的一维数组和二维数组,包括它们的定义、初始化、元素访问以及内存存储等方面的内容。 …...
从零构建云原生秒杀系统——后端架构与实战
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:秒杀系统的挑战与机遇 在电商、票务、抢购等业务场景中,“秒杀”系统扮演着至关重要的角色。 秒杀活动通常会在极短时间内爆发出数十倍至数百倍的平时流量,这对后端系统的承载能力、响应…...
Linux Socket编程:从API到实战
Linux Socket编程完全指南:从API到实战 概述 Socket(套接字)是网络编程的基础,它允许不同主机或同一主机上的不同进程之间进行通信。在Linux系统中,Socket编程主要通过一系列系统调用来实现,这些API提供了…...
德州仪器(TI)—TDA4VM芯片详解(1)—产品特性
写在前面 本系列文章主要讲解德州仪器(TI)TDA4VM芯片的相关知识,希望能帮助更多的同学认识和了解德州仪器(TI)TDA4VM芯片。 若有相关问题,欢迎评论沟通,共同进步。(*^▽^*) 错过其他章节的同学…...
增强版wps-plugin-deepseek开源插件是DeepSeek 支持的 WPS 插件,在您的办公工作流程中提供智能文档自动化和 AI 驱动的生产力增强
一、软件介绍 文末提供程序和源码下载学习 增强版wps-plugin-deepseek开源插件专为WPS Office插件开发打造的Vue模板,搭配Vite构建工具,提供丰富的WPS API实操示例。虽然官方提供了TypeScript扩展包,但支持程度有限,因此本项目选…...
在 Cursor 中 配置 GitHub MCP Server
文章目录 1、简单回顾 sequentialthinking 的安装2、提出问题:如何在 cursor 配置 github mcp 呢3、结果如下How to Configure GitHub MCP in CursorPrerequisitesStep 1: Update Cursor (if needed)Step 2: Generate a GitHub Personal Access TokenStep 3: Open Cursor MCP S…...
uniapp-商城-40-shop 购物车 选好了 进行订单确认4 配送方式3 地址编辑
前面说了配送 和地址页面 当地址页面为空或需要添加地址时,需要添加地址。 我的地址页面有个按钮 就是添加地址 点击 添加地址 按钮 后,就会跳转到地址添加的页面 1、添加地址页面 2、添加地址文件夹以及文件的创建 3、添加地址的代码 <template…...
初步自定义layui的table(laravel 12)
layui的table是非常好的表格,有美观的样式,对接起来也很便捷。使用后端翻页传过来的数据,本地测试是好的,部署到服务器时,翻页不起作用。故而暂时采用一次性读取全部数据,发送给table,界面如下所…...
手写SpringMVC(基本框架)
服务器启动阶段处理 分析服务器启动阶段都都需要初始化什么? 1.初始化Spring容器 组件扫描包下的类纳入IOC容器管理创建视图解析器对象创建所有的拦截器对象扫描这和包下的所有类org.myspringmvc.web.servlet.mvc.method.annotation,全部实例化&#…...
JS-OCR-demo加载本地文件
背景: 在了解 Tesseract 的识别效果的时候,有个demo项目很好用。有个小毛病,就是没事都要从摄像头抓取图片,然后进行识别。如果可以从本地读取图,就更方便了。 实现: 下载项目代码:https://gi…...
MySQL 表的约束(一)
文章目录 表的约束空属性默认值列描述zerofill主键总结 表的约束 1. 为什么要有表的约束? 因为要保证数据的完整性和可约束性,合法性 空属性 两个值:null(默认的)和not null(不为空)数据库默认字段基本都是字段为空…...
论文导读 - 基于大规模测量与多任务深度学习的电子鼻系统实现目标识别、浓度预测与状态判断
基于大规模测量与多任务深度学习的电子鼻系统实现目标识别、浓度预测与状态判断 原论文地址:https://www.sciencedirect.com/science/article/abs/pii/S0925400521014830 引用此论文(GB/T 7714-2015): WANG T, ZHANG H, WU Y, …...
力扣hot100_子串_python版本
一、560. 和为 K 的子数组 思路:这就是一道典型的前缀和的题代码: class Solution:def subarraySum(self, nums: List[int], k: int) -> int:presum [0] * (len(nums) 1)for i, x in enumerate(nums):presum[i 1] presum[i] x # 前缀和序列需要n1个ans 0…...
cached-property - 类属性缓存装饰器
本文翻译整理自:https://github.com/pydanny/cached-property 文章目录 一、关于 cached-property相关链接资源关键功能特性 二、安装三、使用指南1、基础用法2、手动清除缓存3、线程安全版本4、异步支持5、缓存超时(TTL) 四、致谢 一、关于…...
「Mac畅玩AIGC与多模态03」部署篇02 - 在 Mac 上部署 Dify
一、概述 本篇介绍如何在 macOS 环境下本地部署 Dify 平台,作为多模型协同与工作流集成的可视化应用服务。Dify 提供了模型调用、对话管理、知识库问答、插件服务等功能,可与 Ollama、OpenAI、DeepSeek 等推理后端集成,适用于本地智能体应用的快速搭建与扩展。 二、部署流…...
扩散模型和马尔科夫链
1. 扩散模型的基本原理 扩散模型的灵感来源于热力学扩散(如一滴墨水在水中逐渐扩散的过程),其核心分为两个阶段: 前向过程(Forward Process):逐步向数据添加噪声,直到数据完全变为随…...
Dify框架面试内容整理-Dify如何处理知识库的集成?
Dify 在知识库集成方面采用了“检索增强生成(RAG)”的技术架构,核心实现思路如下: 一、知识库集成的整体流程 Dify处理知识库集成通常包括以下关键步骤: 文档上传↓...
第35课 常用快捷操作——用“鼠标左键”拖动图元
概述 拖动某个图元,是设计过程中常需要用到的操作,我们可以在原理图中拖动某个元器件符号,也可以在PCB图中拖动某个焊盘。 和常用的软件类似,用按住鼠标左键的方式来完成拖动操作。 用鼠标左键拖动图元 在想要拖动的图元上&…...
复盘笔记1
以下是一份专业股市投资操盘手的复盘清单,涵盖市场分析、交易策略、风险管理等核心环节,帮助系统化梳理每日交易并优化次日决策: --- ### **一、市场整体复盘** 1. **指数与成交量分析** - 主要指数表现(上证、深证、创业板、科…...
海思dump图原理
在海思中是用指令进行对应的dump。 例如./vi_chn_dump 0 0 1 1 第一个指令代表是dump哪里的数据。 第一个0代表是vi_pipe。 第二个0代表vi_chn。 第一个1代表需要dump帧的数量。 第二个dump代表dump帧的位置,如果是0表示dump的是在所有ISP模块后面的数据࿰…...
C++:STL——list
一简介 底层是一个带头双向循环列表 二、成员函数 (1)构造函数 三、迭代器 四、修饰函数 (1)insert 插入和删除不再使用下标,而是使用迭代器指针作为要插入位置的形参,这是因为:vector是连续的…...
在Azure Databricks中实现缓慢变化维度(SCD)的三种类型
在Azure Databricks中使用PySpark实现缓慢变化维度(SCD)的三种核心类型,需结合Spark SQL和DataFrame API的特性,并利用Delta Lake的事务支持。以下是具体设计与实现步骤,以及测试用例: 通过以下步骤&#…...
Segment Anything in Images and Videos
目录 摘要 Abstract SAM2 模型框架 图像编码器 记忆机制 提示编码器和掩码解码器 实验 代码 总结 摘要 SAM2是基于Meta公司推出的Segment Anything Model升级而来的先进分割模型。它在SAM的基础上,通过引入记忆注意力模块和优化图像编码器等改进…...
C++之异常
目录 一、异常的概念及使用 1.1、异常的概念 1.2、异常的抛出和捕获 1.3、栈展开 1.4、查找匹配的处理代码 1.5、异常重新抛出 1.6、异常安全问题 1.7、异常规范 1.8、C异常的优缺点 二、标准库的异常 一、异常的概念及使用 1.1、异常的概念 异常处理机制允许程序中…...
服务器不能复制粘贴文件的处理方式
1.打开远程的服务器,在服务器的任务栏随便一块空白处右击鼠标,选择“启动任务管理器”。 2.在打开的任务管理器中,我们找到“rdpclip.exe”这个进程,如果没有找到那么如图所示 任务管理器–文件–运行新任务,然后在弹出的对话框内输入rdpclip.exe 如下图࿱…...
Golang | 搜索表达式
// (( A | B | C ) & D ) | E & (( F | G ) & H )import "strings"// 实例化一个搜索表达式 func NewTermQuery(field, keyword string) *TermQuery {return &TermQuery{Keyword: &Keyword{Field: field, Word: keyword},} }func (tq *TermQuery…...
【速写】conda安装(linux)
序言 昨天叶凯浩空降(全马241),降维打击,10分24秒断层夺冠。 夏潇阳10分53秒绝杀小崔10分54秒第2,小崔第3,均配都在3’30"以内,即便我是去年巅峰期也很难跑出这种水平。我就知道他去年大…...
linux两个特殊的宏 _RET_IP_ 和_THIS_IP_ 实现
本文探讨了Linux环境下两个特殊的宏,_RET_IP_和_THIS_IP_,它们分别用于获取当前函数的返回地址和当前指令指针的地址。 1、宏定义 我们先看它们的宏定义 include./linux/kernel.h#define _RET_IP_ (unsigned long)__builtin_return_address(0)#define _THIS_IP_ ({ __labe…...
开源|上海AILab:自动驾驶仿真平台LimSim Series,兼容端到端/知识驱动/模块化技术路线
导读 随着自动驾驶技术快速发展,有效的仿真环境成为验证与增强这些系统的关键。来自上海人工智能实验室的研究团队推出了LimSim Series——一个革命性的自动驾驶仿真平台,它巧妙解决了行业面临的三大挑战:仿真精度与持续时间的平衡、功能性与…...
全栈黑暗物质:可观测性之外的非确定性调试
一、量子计算的测不准Bug 1. 经典 vs. 量子系统的错误模式 量子程序崩溃的观测影响: 调试方法崩溃复现率观测干扰度日志打印12%35%断点调试5%78%无侵入跟踪27%9%量子态层析成像63%2% 二、量子调试工具箱 1. 非破坏性观测协议 # 量子程序的无干扰快照 from qiski…...
光耦、继电器
一、光耦 1.什么是光耦? ①图一:Ic受控于Ib,间接受控于Ia ②如果Va和Vb是隔离的两个电压系统该咋控制?可以利用光耦来控制,让两边建立关系 2.光电耦合器的基本原理 ①是以光为媒介来传输电信号的器件,通常把发光器…...
使用Three.js搭建自己的3Dweb模型(从0到1无废话版本)
教学视频参考:B站——Three.js教学 教学链接:Three.js中文网 老陈打码 | 麒跃科技 一.什么是Three.js? Three.js 是一个基于 JavaScript 的 3D 图形库,用于在网页浏览器中创建和渲染交互式 3D 内容。它基于 WebGL࿰…...
Redis远程链接应用案例
1.配置文件设置 打开配置文件redis.windows.conf,配置以下内容: 1.bind 0.0.0.0(设置所有IP可访问) 2.requirepass 1234.com(密码设置) 3.protected-mode no(远程可访问) 2.防火…...
STM32 定时器TIM
定时器基础知识 定时器就是用来定时的机器,是存在于STM32单片机中的一个外设。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM6、TIM7),如下图所示: STM32F1…...
基于大模型的急性化脓性阑尾炎全程诊疗预测与方案研究
目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目标与方法 二、大模型技术原理与应用基础 2.1 大模型概述 2.2 相关技术原理 2.3 数据收集与预处理 三、术前风险预测与准备 3.1 病情评估指标分析 3.2 大模型预测方法与结果 3.3 术前准备方案 四、…...
第一个 servlet请求
文章目录 前端后端前后端 产生 联系 前端 后端 package com.yanyu;import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;import java.io.I…...
XLSX.utils.sheet_to_json设置了blankrows:true,但无法获取到开头的空白行
在用sheetJs的XLSX库做导入,遇到一个bug。如果开头行是空白行的话,调用sheet_to_json转数组获得的数据也是没有包含空白行的。这样会导致在设置对应的起始行时,解析数据不生效。 目前是直接跳过了开头的两行空白行 正确应该获得一下数据 问…...
python一款简单的数据库同步dts小实现
一、实现说明 在数据开发与运维场景中,数据库同步是一项基础且高频的需求。无论是开发环境与生产环境的数据镜像,还是多数据库之间的数据分发,都需要可靠的同步工具。本文将基于 Python 和pymysql库,实现一个轻量级数据库同步工具…...
误触网络重置,笔记本电脑wifi连接不上解决方法(Win10,Win11通用)
笔记本电脑连接不上网,有人说网络重置按钮可以解决,结果把wifi图标都给搞没了,只剩飞行模式,解决方法(错误码39),罪魁祸首就是这个网络重置,一下连网络都检测不到了 那么没有网络怎…...
markdown-it-katex 安装和配置指南
markdown-it-katex 是一个用于 Markdown-it 的插件,旨在通过 KaTeX 库在 Markdown 文档中添加数学公式支持。KaTeX 是一个快速渲染数学公式的库,相比于 MathJax,它在性能上有显著优势。 步骤 1: 安装 Markdown-it 首先,你需要安装…...
开源财务软件:企业财务数字化转型的有力工具
在当今数字化时代,企业财务数字化转型已成为必然趋势。随着业务的不断拓展和复杂化,企业对财务软件的需求也在日益增长。然而,传统商业财务软件往往伴随着高昂的授权费用和有限的定制化能力,这让许多企业,尤其是中小企…...
大模型——Suna集成浏览器操作与数据分析的智能代理
大模型——Suna集成浏览器操作与数据分析的智能代理 Suna 是 Kortix AI 开发的一个开源通用 AI 代理,托管在 GitHub 上,基于 Apache 2.0 许可证,允许用户免费下载、修改和自托管。它通过自然语言对话帮助用户完成复杂任务,如网页浏览、文件管理、数据抓取和网站部署。Suna…...
QT中的事件及其属性
Qt中的事件是对操作系统提供的事件机制进行封装,Qt中的信号槽就是对事件机制的进一步封装 但是特殊情况下,如对于没有提供信号的用户操作,就需要通过重写事件处理的形式,来手动处理事件的响应逻辑 常见的Qt事件: 常见事…...