kanq-erp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kanq-erp might be problematic. Click here for more details.
- kanq_erp-0.1.0/PKG-INFO +9 -0
- kanq_erp-0.1.0/README.md +0 -0
- kanq_erp-0.1.0/kanq_erp/__init__.py +32 -0
- kanq_erp-0.1.0/kanq_erp/browser_manager.py +51 -0
- kanq_erp-0.1.0/kanq_erp/day_report.py +77 -0
- kanq_erp-0.1.0/kanq_erp/element_utils.py +53 -0
- kanq_erp-0.1.0/kanq_erp/erp.py +173 -0
- kanq_erp-0.1.0/kanq_erp/llm_summary.py +99 -0
- kanq_erp-0.1.0/kanq_erp/week_plan.py +67 -0
- kanq_erp-0.1.0/kanq_erp.egg-info/PKG-INFO +9 -0
- kanq_erp-0.1.0/kanq_erp.egg-info/SOURCES.txt +15 -0
- kanq_erp-0.1.0/kanq_erp.egg-info/dependency_links.txt +1 -0
- kanq_erp-0.1.0/kanq_erp.egg-info/entry_points.txt +2 -0
- kanq_erp-0.1.0/kanq_erp.egg-info/requires.txt +3 -0
- kanq_erp-0.1.0/kanq_erp.egg-info/top_level.txt +1 -0
- kanq_erp-0.1.0/pyproject.toml +17 -0
- kanq_erp-0.1.0/setup.cfg +4 -0
kanq_erp-0.1.0/PKG-INFO
ADDED
kanq_erp-0.1.0/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@File : __init__.py.py
|
|
3
|
+
@Time : 2026/1/27 上午11:57
|
|
4
|
+
@Author : xiashuobad
|
|
5
|
+
@Desc :
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* _ooOoo_
|
|
9
|
+
* o8888888o
|
|
10
|
+
* 88" . "88
|
|
11
|
+
* (| -_- |)
|
|
12
|
+
* O\ = /O
|
|
13
|
+
* ___/`---'\____
|
|
14
|
+
* . ' \\| |// `.
|
|
15
|
+
* / \\||| : |||// \
|
|
16
|
+
* / _||||| -:- |||||- \
|
|
17
|
+
* | | \\\ - /// | |
|
|
18
|
+
* | \_| ''\---/'' | |
|
|
19
|
+
* \ .-\__ `-` ___/-. /
|
|
20
|
+
* ___`. .' /--.--\ `. . __
|
|
21
|
+
* ."" '< `.___\_<|>_/___.' >'"".
|
|
22
|
+
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
|
|
23
|
+
* \ \ `-. \_ __\ /__ _/ .-` / /
|
|
24
|
+
* ======`-.____`-.___\_____/___.-`____.-'======
|
|
25
|
+
* `=---=' bug泛滥 佛已瘫痪
|
|
26
|
+
"""
|
|
27
|
+
from .erp import app
|
|
28
|
+
from .browser_manager import BrowserManager
|
|
29
|
+
from .day_report import DayReportHandler
|
|
30
|
+
from .element_utils import ElementUtils
|
|
31
|
+
from .llm_summary import LLMSummarizer
|
|
32
|
+
from .week_plan import WeekPlanHandler
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: xiash$
|
|
3
|
+
Date: 2026/1/26$
|
|
4
|
+
Project: week_plan$
|
|
5
|
+
Description: $
|
|
6
|
+
***
|
|
7
|
+
* _ooOoo_
|
|
8
|
+
* o8888888o
|
|
9
|
+
* 88" . "88
|
|
10
|
+
* (| -_- |)
|
|
11
|
+
* O\ = /O
|
|
12
|
+
* ___/`---'\____
|
|
13
|
+
* . ' \\| |// `.
|
|
14
|
+
* / \\||| : |||// \
|
|
15
|
+
* / _||||| -:- |||||- \
|
|
16
|
+
* | | \\\ - /// | |
|
|
17
|
+
* | \_| ''\---/'' | |
|
|
18
|
+
* \ .-\__ `-` ___/-. /
|
|
19
|
+
* ___`. .' /--.--\ `. . __
|
|
20
|
+
* ."" '< `.___\_<|>_/___.' >'"".
|
|
21
|
+
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
|
|
22
|
+
* \ \ `-. \_ __\ /__ _/ .-` / /
|
|
23
|
+
* ======`-.____`-.___\_____/___.-`____.-'======
|
|
24
|
+
* `=---='
|
|
25
|
+
* .............................................
|
|
26
|
+
* 佛曰:bug泛滥,我已瘫痪!
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# browser_manager.py
|
|
30
|
+
from DrissionPage import Chromium, ChromiumOptions
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class BrowserManager:
|
|
34
|
+
def __init__(self, browser_path=None):
|
|
35
|
+
self.browser_path = browser_path
|
|
36
|
+
self.tab = None
|
|
37
|
+
|
|
38
|
+
def initialize(self):
|
|
39
|
+
co = ChromiumOptions()
|
|
40
|
+
self.browser_path and co.set_browser_path(self.browser_path)
|
|
41
|
+
self.tab = Chromium(co).new_tab()
|
|
42
|
+
return self.tab
|
|
43
|
+
|
|
44
|
+
def login(self, url, username, password):
|
|
45
|
+
self.tab.get(url)
|
|
46
|
+
ele_username = self.tab.ele('#username', timeout=5)
|
|
47
|
+
if ele_username:
|
|
48
|
+
ele_username.input(username)
|
|
49
|
+
self.tab.ele('#password').input(password)
|
|
50
|
+
self.tab.ele('#submit').click()
|
|
51
|
+
return ele_username, self.tab.ele('#homeid')
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# day_report.py
|
|
2
|
+
from .element_utils import ElementUtils
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DayReportHandler:
|
|
6
|
+
def __init__(self, browser_manager):
|
|
7
|
+
self.browser = browser_manager
|
|
8
|
+
self.tab = browser_manager.tab
|
|
9
|
+
|
|
10
|
+
def navigate_to_day_report(self):
|
|
11
|
+
ElementUtils.safe_click(self.tab, '@class=workReport-true')
|
|
12
|
+
|
|
13
|
+
def select_task(self, task_name):
|
|
14
|
+
row = self.tab.ele(f'xpath://table//tr[td="{task_name}"]')
|
|
15
|
+
self.tab.actions.move_to(row).click(times=2)
|
|
16
|
+
|
|
17
|
+
return float(row.eles('tag:td')[4].text.strip())
|
|
18
|
+
|
|
19
|
+
def get_progress_value(self, task_name):
|
|
20
|
+
form = self.tab.ele('@name=任务汇报明细')
|
|
21
|
+
row = form.ele(f'xpath://table//tr[td="{task_name}"]')
|
|
22
|
+
return float(row.eles('tag:td')[7].text.strip() or 0)
|
|
23
|
+
|
|
24
|
+
def open_report_form(self):
|
|
25
|
+
span = self.tab.ele('@title=任务汇报')
|
|
26
|
+
self.tab.actions.move_to(span).click()
|
|
27
|
+
|
|
28
|
+
def fill_report_form(
|
|
29
|
+
self,
|
|
30
|
+
description: str,
|
|
31
|
+
completion_rate: float,
|
|
32
|
+
date: str = None,
|
|
33
|
+
location: str = '武汉技术中心',
|
|
34
|
+
task_type: str = '需求开发',
|
|
35
|
+
quality: str = '优',
|
|
36
|
+
workload: float = 8.00
|
|
37
|
+
):
|
|
38
|
+
ElementUtils.safe_input(self.tab, '#65_text', date)
|
|
39
|
+
ElementUtils.safe_input(self.tab, '@name=工作地点', location)
|
|
40
|
+
ElementUtils.safe_input(self.tab, '@name=任务类型_text', task_type)
|
|
41
|
+
|
|
42
|
+
dropdown = self.tab.ele('@class=co-combo-down')
|
|
43
|
+
dropdown.click()
|
|
44
|
+
option = self.tab.wait.ele_displayed(f'text={quality}', timeout=3)
|
|
45
|
+
option.click.left(by_js=True)
|
|
46
|
+
|
|
47
|
+
ElementUtils.safe_input(self.tab, '@name=当日投入工作量', f"{workload:.2f}")
|
|
48
|
+
ElementUtils.safe_input(self.tab, '@name=完成率', f'{completion_rate:.2f}')
|
|
49
|
+
ElementUtils.safe_input(self.tab, '@name=工作内容描述', description)
|
|
50
|
+
|
|
51
|
+
def submit_report(self):
|
|
52
|
+
confirm_button = self.tab.wait.ele_displayed('@class=co-win-button co-alert-button', timeout=1)
|
|
53
|
+
if confirm_button:
|
|
54
|
+
confirm_button.click.left(by_js=True)
|
|
55
|
+
ElementUtils.safe_click(self.tab, '@onclick=33-6-4')
|
|
56
|
+
print('报工完成!')
|
|
57
|
+
|
|
58
|
+
# def main():
|
|
59
|
+
# browser = BrowserManager()
|
|
60
|
+
# browser.initialize()
|
|
61
|
+
# browser.login('http://erp.kqgeo.com:889/cops/home/index.jsp', 'xiangsong', 'Xs135456')
|
|
62
|
+
#
|
|
63
|
+
# handler = DayReportHandler(browser)
|
|
64
|
+
# handler.navigate_to_day_report()
|
|
65
|
+
# handler.select_task('解译平台功能研发与维护')
|
|
66
|
+
# progress_value = handler.get_progress_value('解译平台功能研发与维护')
|
|
67
|
+
# handler.open_report_form()
|
|
68
|
+
#
|
|
69
|
+
# handler.fill_report_form(
|
|
70
|
+
# completion_rate=progress_value + 0.1,
|
|
71
|
+
# description='666666666666666666666666666666666666666666666666'
|
|
72
|
+
# )
|
|
73
|
+
# handler.submit_report()
|
|
74
|
+
#
|
|
75
|
+
#
|
|
76
|
+
# if __name__ == '__main__':
|
|
77
|
+
# main()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: xiash$
|
|
3
|
+
Date: 2026/1/26$
|
|
4
|
+
Project: week_plan$
|
|
5
|
+
Description: $
|
|
6
|
+
***
|
|
7
|
+
* _ooOoo_
|
|
8
|
+
* o8888888o
|
|
9
|
+
* 88" . "88
|
|
10
|
+
* (| -_- |)
|
|
11
|
+
* O\ = /O
|
|
12
|
+
* ___/`---'\____
|
|
13
|
+
* . ' \\| |// `.
|
|
14
|
+
* / \\||| : |||// \
|
|
15
|
+
* / _||||| -:- |||||- \
|
|
16
|
+
* | | \\\ - /// | |
|
|
17
|
+
* | \_| ''\---/'' | |
|
|
18
|
+
* \ .-\__ `-` ___/-. /
|
|
19
|
+
* ___`. .' /--.--\ `. . __
|
|
20
|
+
* ."" '< `.___\_<|>_/___.' >'"".
|
|
21
|
+
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
|
|
22
|
+
* \ \ `-. \_ __\ /__ _/ .-` / /
|
|
23
|
+
* ======`-.____`-.___\_____/___.-`____.-'======
|
|
24
|
+
* `=---='
|
|
25
|
+
* .............................................
|
|
26
|
+
* 佛曰:bug泛滥,我已瘫痪!
|
|
27
|
+
"""
|
|
28
|
+
import time
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# element_utils.py
|
|
32
|
+
class ElementUtils:
|
|
33
|
+
@staticmethod
|
|
34
|
+
def safe_input(tab, selector, text, clear=True):
|
|
35
|
+
element = tab.ele(selector)
|
|
36
|
+
if element and text:
|
|
37
|
+
element.input(text, clear=clear)
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def safe_click(tab, selector, timeout=10):
|
|
41
|
+
element = tab.wait.ele_displayed(selector, timeout=timeout)
|
|
42
|
+
if element:
|
|
43
|
+
time.sleep(1)
|
|
44
|
+
element.click()
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def safe_get_text(tab, selector, default=''):
|
|
48
|
+
"""等待元素显示并获取文本"""
|
|
49
|
+
element = tab.wait.ele_displayed(selector)
|
|
50
|
+
if element:
|
|
51
|
+
text = element.property('value').strip()
|
|
52
|
+
return text if text else default
|
|
53
|
+
return default
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: xiash$
|
|
3
|
+
Date: 2026/1/26$
|
|
4
|
+
Project: week_plan$
|
|
5
|
+
Description: $
|
|
6
|
+
***
|
|
7
|
+
* _ooOoo_
|
|
8
|
+
* o8888888o
|
|
9
|
+
* 88" . "88
|
|
10
|
+
* (| -_- |)
|
|
11
|
+
* O\ = /O
|
|
12
|
+
* ___/`---'\____
|
|
13
|
+
* . ' \\| |// `.
|
|
14
|
+
* / \\||| : |||// \
|
|
15
|
+
* / _||||| -:- |||||- \
|
|
16
|
+
* | | \\\ - /// | |
|
|
17
|
+
* | \_| ''\---/'' | |
|
|
18
|
+
* \ .-\__ `-` ___/-. /
|
|
19
|
+
* ___`. .' /--.--\ `. . __
|
|
20
|
+
* ."" '< `.___\_<|>_/___.' >'"".
|
|
21
|
+
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
|
|
22
|
+
* \ \ `-. \_ __\ /__ _/ .-` / /
|
|
23
|
+
* ======`-.____`-.___\_____/___.-`____.-'======
|
|
24
|
+
* `=---='
|
|
25
|
+
* .............................................
|
|
26
|
+
* 佛曰:bug泛滥,我已瘫痪!
|
|
27
|
+
"""
|
|
28
|
+
import typer
|
|
29
|
+
import os
|
|
30
|
+
import sys
|
|
31
|
+
from dotenv import load_dotenv, set_key
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from DrissionPage.errors import ElementNotFoundError
|
|
34
|
+
|
|
35
|
+
from .browser_manager import BrowserManager
|
|
36
|
+
|
|
37
|
+
app = typer.Typer()
|
|
38
|
+
|
|
39
|
+
# 环境变量配置文件路径
|
|
40
|
+
ENV_FILE = Path.home() / ".erp_env"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ensure_env_file():
|
|
44
|
+
"""确保环境变量文件存在"""
|
|
45
|
+
if not ENV_FILE.exists():
|
|
46
|
+
ENV_FILE.touch()
|
|
47
|
+
set_key(ENV_FILE, 'ERP_URL', 'http://erp.kqgeo.com:889/cops/home/index.jsp')
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def save_env(key, value=None):
|
|
51
|
+
"""保存环境变量"""
|
|
52
|
+
if value is not None:
|
|
53
|
+
set_key(ENV_FILE, key, value)
|
|
54
|
+
else:
|
|
55
|
+
set_key(ENV_FILE, key, typer.prompt(f'请输入 {key}'))
|
|
56
|
+
# 重新加载环境变量
|
|
57
|
+
load_dotenv(ENV_FILE)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_env_value(key, prompt=True):
|
|
61
|
+
"""获取环境变量值"""
|
|
62
|
+
load_dotenv(ENV_FILE)
|
|
63
|
+
value = os.environ.get(key, None)
|
|
64
|
+
if value is None and prompt:
|
|
65
|
+
value = typer.prompt(f"请输入 {key.lower()}")
|
|
66
|
+
save_env(key, value)
|
|
67
|
+
|
|
68
|
+
return value
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def retry_login(browser: BrowserManager, erp_url, username, password, try_times=3):
|
|
72
|
+
for i in range(try_times):
|
|
73
|
+
login_flag, index_flag = browser.login(erp_url, username, password)
|
|
74
|
+
if index_flag:
|
|
75
|
+
break
|
|
76
|
+
elif i == try_times - 1:
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
elif not login_flag and not index_flag:
|
|
79
|
+
erp_url = typer.prompt('erp地址有误!请输入新的erp地址')
|
|
80
|
+
set_key(ENV_FILE, 'ERP_URL', erp_url)
|
|
81
|
+
else:
|
|
82
|
+
print('用户或密码错误!')
|
|
83
|
+
username = typer.prompt(f'请输入用户名')
|
|
84
|
+
password = typer.prompt('请输入密码')
|
|
85
|
+
set_key(ENV_FILE, 'ERP_USERNAME', username)
|
|
86
|
+
set_key(ENV_FILE, 'ERP_PASSWORD', password)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def login_erp(erp_url=None, browser_path=None):
|
|
90
|
+
ensure_env_file()
|
|
91
|
+
if browser_path:
|
|
92
|
+
set_key(ENV_FILE, 'BROWSER_PATH', browser_path)
|
|
93
|
+
browser = BrowserManager(get_env_value('BROWSER_PATH', prompt=False))
|
|
94
|
+
try:
|
|
95
|
+
browser.initialize()
|
|
96
|
+
except FileNotFoundError:
|
|
97
|
+
print('无法自动找到浏览器程序,请通过 --浏览器 参数手动指定程序路径(一次指定,永久更新)')
|
|
98
|
+
sys.exit(1)
|
|
99
|
+
|
|
100
|
+
if erp_url:
|
|
101
|
+
set_key(ENV_FILE, 'ERP_URL', erp_url)
|
|
102
|
+
erp_url = get_env_value('ERP_URL')
|
|
103
|
+
username = get_env_value('ERP_USERNAME')
|
|
104
|
+
password = get_env_value('ERP_PASSWORD')
|
|
105
|
+
retry_login(browser, erp_url, username, password)
|
|
106
|
+
return browser
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def validate_report_length(text: str):
|
|
110
|
+
if len(text) < 15:
|
|
111
|
+
raise typer.BadParameter("工作内容描述不得少于15字!")
|
|
112
|
+
return text
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def all_task_type():
|
|
116
|
+
return ['需求开发', '系统设计', '系统搭建', '编码实现', '数据处理', '系统测试', '系统缺陷修改', '项目验收',
|
|
117
|
+
'技术文档编写', '项目管理', '技术评审', '会议', '技术培训', '其他', '售前演示交流', '方案撰写']
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@app.command('报工')
|
|
121
|
+
def day_report(
|
|
122
|
+
text: str = typer.Argument(None, callback=validate_report_length, help='报工内容'),
|
|
123
|
+
# complete_rate: float = typer.Option(None, '--进度', help='项目完成进度', min=0, max=100),
|
|
124
|
+
task_name: str = typer.Option(None, '--任务', help='任务名称'),
|
|
125
|
+
date: str = typer.Option(None, '--日期', help='日期,格式:2026-01-26,默认为当天'),
|
|
126
|
+
location: str = typer.Option('武汉技术中心', '--地点', help='报工地点'),
|
|
127
|
+
task_type: str = typer.Option('需求开发', '--类型', autocompletion=all_task_type, help='任务类型'),
|
|
128
|
+
workload: float = typer.Option(8., '--时长', help='报工时长', min=0.5),
|
|
129
|
+
erp_url: str = typer.Option(None, '--网址', help='erp网址,有默认值,当网址发生变化时,可设置更新'),
|
|
130
|
+
browser_path: str = typer.Option(None, '--浏览器', help='浏览器程序exe文件所在路径,默认使用谷歌浏览器')
|
|
131
|
+
):
|
|
132
|
+
from .day_report import DayReportHandler
|
|
133
|
+
|
|
134
|
+
browser = login_erp(erp_url, browser_path)
|
|
135
|
+
handler = DayReportHandler(browser)
|
|
136
|
+
handler.navigate_to_day_report()
|
|
137
|
+
if task_name:
|
|
138
|
+
set_key(ENV_FILE, 'TASK_NAME', task_name)
|
|
139
|
+
try:
|
|
140
|
+
total_complete_rate = handler.select_task(get_env_value('TASK_NAME'))
|
|
141
|
+
progress_value = handler.get_progress_value(get_env_value('TASK_NAME'))
|
|
142
|
+
except ElementNotFoundError:
|
|
143
|
+
print('任务名称有误!请通过参数 --任务 设置更新要报工的任务(只需设置一次),名称不要用单引号!')
|
|
144
|
+
sys.exit(1)
|
|
145
|
+
handler.open_report_form()
|
|
146
|
+
|
|
147
|
+
handler.fill_report_form(
|
|
148
|
+
completion_rate=min(max(progress_value, total_complete_rate) + 0.1, 100.),
|
|
149
|
+
description=text,
|
|
150
|
+
date=date,
|
|
151
|
+
location=location,
|
|
152
|
+
task_type=task_type,
|
|
153
|
+
workload=workload
|
|
154
|
+
)
|
|
155
|
+
handler.submit_report()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@app.command('周计划')
|
|
159
|
+
def week_plan(
|
|
160
|
+
erp_url: str = typer.Option(None, '--网址', help='erp网址,有默认值,当网址发生变化时,可设置更新'),
|
|
161
|
+
browser_path: str = typer.Option(None, '--浏览器', help='浏览器程序exe文件所在路径,默认使用谷歌浏览器')
|
|
162
|
+
):
|
|
163
|
+
from .week_plan import WeekPlanHandler
|
|
164
|
+
|
|
165
|
+
browser = login_erp(erp_url, browser_path)
|
|
166
|
+
|
|
167
|
+
handler = WeekPlanHandler(browser)
|
|
168
|
+
handler.navigate_to_week_plan()
|
|
169
|
+
all_reports = handler.collect_daily_reports()
|
|
170
|
+
week_report = handler.generate_week_summary(all_reports)
|
|
171
|
+
next_week_plan = handler.generate_next_week_plan(week_report)
|
|
172
|
+
handler.fill_week_reports(week_report, next_week_plan)
|
|
173
|
+
handler.save_report()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from DrissionPage import Chromium, ChromiumOptions
|
|
3
|
+
from DrissionPage._functions.keys import Keys
|
|
4
|
+
|
|
5
|
+
LLM_URL = 'https://www.qianwen.com/'
|
|
6
|
+
DEFAULT_PROMPT = ("帮我总结一下上面的报工,按项目名称分类,项目名称中关键字重复度高的视为同一个项目,"
|
|
7
|
+
"直接给出结果,返回格式为:1.项目1:。。。一段话;2.项目2:。。。一段话;3.项目3:。。。。,"
|
|
8
|
+
"注意:报工中每行冒号前面就是项目名,结果中请不要出现报工中没有的项目名!!!")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LLMSummarizer:
|
|
12
|
+
"""LLM摘要生成器类,用于使用千问大模型生成文本摘要,支持上下文管理器"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, headless: bool = True, browser_path: Optional[str] = None):
|
|
15
|
+
"""
|
|
16
|
+
初始化LLM摘要生成器
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
headless: 是否使用无头模式,默认为True
|
|
20
|
+
browser_path: 浏览器可执行文件路径,如果为None则使用默认路径
|
|
21
|
+
"""
|
|
22
|
+
self.headless = headless
|
|
23
|
+
self.browser_path = browser_path
|
|
24
|
+
self.tab = None
|
|
25
|
+
|
|
26
|
+
def initialize(self) -> None:
|
|
27
|
+
"""初始化浏览器和标签页"""
|
|
28
|
+
co = ChromiumOptions()
|
|
29
|
+
if self.headless:
|
|
30
|
+
co.headless()
|
|
31
|
+
if self.browser_path:
|
|
32
|
+
co.set_browser_path(self.browser_path)
|
|
33
|
+
|
|
34
|
+
self.tab = Chromium(co).new_tab()
|
|
35
|
+
self.tab.get(LLM_URL)
|
|
36
|
+
|
|
37
|
+
def summarize(self, text: str, prompt: Optional[str] = None) -> str:
|
|
38
|
+
"""
|
|
39
|
+
生成文本摘要
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
text: 需要摘要的文本
|
|
43
|
+
prompt: 提示词,如果为None则使用默认提示词
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: 生成的摘要文本
|
|
47
|
+
"""
|
|
48
|
+
if not self.tab:
|
|
49
|
+
self.initialize()
|
|
50
|
+
|
|
51
|
+
# 如果没有提供提示词,使用默认提示词
|
|
52
|
+
if not prompt:
|
|
53
|
+
prompt = DEFAULT_PROMPT
|
|
54
|
+
|
|
55
|
+
# 构建完整的输入文本
|
|
56
|
+
contents = f"{text}\n\n{prompt}{Keys.ENTER}"
|
|
57
|
+
|
|
58
|
+
# 输入文本到文本框
|
|
59
|
+
self.tab.ele('text=向千问提问').input(contents)
|
|
60
|
+
|
|
61
|
+
self.tab.ele('@class=answerToolsContent-pftvzO', timeout=30)
|
|
62
|
+
|
|
63
|
+
# 获取结果
|
|
64
|
+
qk_texts = '\n'.join(map(lambda span: span.text, self.tab.eles('@class=qk-md-text complete')))
|
|
65
|
+
|
|
66
|
+
return qk_texts
|
|
67
|
+
|
|
68
|
+
def close(self) -> None:
|
|
69
|
+
"""关闭浏览器"""
|
|
70
|
+
if self.tab:
|
|
71
|
+
self.tab.close()
|
|
72
|
+
self.tab = None
|
|
73
|
+
|
|
74
|
+
def __enter__(self):
|
|
75
|
+
"""支持上下文管理器,进入with语句块时调用"""
|
|
76
|
+
self.initialize()
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
80
|
+
"""支持上下文管理器,退出with语句块时调用"""
|
|
81
|
+
self.close()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# 使用示例
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
# 使用with语句,自动管理资源
|
|
87
|
+
with LLMSummarizer(headless=False) as summarizer:
|
|
88
|
+
# 需要摘要的文本
|
|
89
|
+
text_to_summarize = """
|
|
90
|
+
BS_AI:继续编写tensorflow后端语义分割遥感影像的推理代码,已初步完成,单进程推理已通过测试,多卡多进程模式还有问题调试中。
|
|
91
|
+
BS_AI:继续调试tensorflow后端语义分割遥感影像的推理代码,逐步排查定位多卡多进程导致的报错问题,问题已找到并解决。
|
|
92
|
+
BS_AI:调试ogc推理代码,成功解决ogc推理报错的问题,主要修改有:wms 1.3.0版本下参数格式的修改,适配1.3.0之前及1.3.0的版本;接触瓦片最大数量的限制,根据geojson的范围去下载影像而不是下载全图,防止内存溢出;修复图像尺寸小于模型推理最小尺寸时报错的bug
|
|
93
|
+
BS_AI:开始编写tensorflow后端目标检测训练的代码,已完成:训练数据加载器dataset的封装;dfine算法模型的构建与封装;数据增强管道的封装。
|
|
94
|
+
BS_AI:调试ogc推理时结果为空的问题,定位问题为rasterio保存的ogc图片未自动刷新缓存导致的结果为空,已修复;继续编写调试tensorflow后端目标检测训练的接口,新增对LinearLR和MultiStepLR学习率调度器的封装,新增mAP指标类的封装。
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
# 生成摘要
|
|
98
|
+
summary = summarizer.summarize(text_to_summarize)
|
|
99
|
+
print(summary)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# week_plan.py
|
|
2
|
+
from .element_utils import ElementUtils
|
|
3
|
+
from .llm_summary import LLMSummarizer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class WeekPlanHandler:
|
|
7
|
+
def __init__(self, browser_manager):
|
|
8
|
+
self.browser = browser_manager
|
|
9
|
+
self.tab = browser_manager.tab
|
|
10
|
+
self.week_days = ['Mon', 'Tues', 'Wed', 'Thur', 'Fri']
|
|
11
|
+
|
|
12
|
+
def navigate_to_week_plan(self):
|
|
13
|
+
ElementUtils.safe_click(self.tab, '#weekly_a')
|
|
14
|
+
ElementUtils.safe_click(self.tab, 'text=提取日志/报工')
|
|
15
|
+
|
|
16
|
+
def collect_daily_reports(self):
|
|
17
|
+
all_reports = []
|
|
18
|
+
for day in self.week_days:
|
|
19
|
+
day_report = ElementUtils.safe_get_text(self.tab, f'#thisWeek{day}_M', '请假')
|
|
20
|
+
ElementUtils.safe_input(self.tab, f'#thisWeek{day}_M', day_report)
|
|
21
|
+
ElementUtils.safe_input(self.tab, f'#thisWeek{day}_A', day_report)
|
|
22
|
+
all_reports.append(day_report)
|
|
23
|
+
return all_reports
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def generate_week_summary(all_reports):
|
|
27
|
+
with LLMSummarizer() as summarizer:
|
|
28
|
+
return summarizer.summarize('\n'.join(all_reports))
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
def generate_next_week_plan(week_report):
|
|
32
|
+
with LLMSummarizer() as summarizer:
|
|
33
|
+
return summarizer.summarize(
|
|
34
|
+
week_report,
|
|
35
|
+
prompt='这是这周的报工内容,帮我生成一下下周计划,直接给出至少十条计划,其他废话不要有!'
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def fill_week_reports(self, week_report, next_week_plan):
|
|
39
|
+
ElementUtils.safe_input(self.tab, '#thisWeekPoint', week_report)
|
|
40
|
+
ElementUtils.safe_input(self.tab, '#nextWeekPoint', next_week_plan)
|
|
41
|
+
|
|
42
|
+
plan_items = next_week_plan.split('\n')
|
|
43
|
+
for i, day in enumerate(self.week_days):
|
|
44
|
+
i *= 2
|
|
45
|
+
ElementUtils.safe_input(self.tab, f'#nextWeek{day}_M', plan_items[i])
|
|
46
|
+
ElementUtils.safe_input(self.tab, f'#nextWeek{day}_A', plan_items[i + 1])
|
|
47
|
+
|
|
48
|
+
def save_report(self):
|
|
49
|
+
ElementUtils.safe_click(self.tab, 'text=保存')
|
|
50
|
+
print('周计划已保存!')
|
|
51
|
+
|
|
52
|
+
# def main():
|
|
53
|
+
# browser = BrowserManager()
|
|
54
|
+
# browser.initialize()
|
|
55
|
+
# browser.login('http://erp.kqgeo.com:889/cops/home/index.jsp', 'xiangsong', 'Xs135456')
|
|
56
|
+
#
|
|
57
|
+
# handler = WeekPlanHandler(browser)
|
|
58
|
+
# handler.navigate_to_week_plan()
|
|
59
|
+
# all_reports = handler.collect_daily_reports()
|
|
60
|
+
# week_report = handler.generate_week_summary(all_reports)
|
|
61
|
+
# next_week_plan = handler.generate_next_week_plan(week_report)
|
|
62
|
+
# handler.fill_week_reports(week_report, next_week_plan)
|
|
63
|
+
# handler.save_report()
|
|
64
|
+
#
|
|
65
|
+
#
|
|
66
|
+
# if __name__ == '__main__':
|
|
67
|
+
# main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
kanq_erp/__init__.py
|
|
4
|
+
kanq_erp/browser_manager.py
|
|
5
|
+
kanq_erp/day_report.py
|
|
6
|
+
kanq_erp/element_utils.py
|
|
7
|
+
kanq_erp/erp.py
|
|
8
|
+
kanq_erp/llm_summary.py
|
|
9
|
+
kanq_erp/week_plan.py
|
|
10
|
+
kanq_erp.egg-info/PKG-INFO
|
|
11
|
+
kanq_erp.egg-info/SOURCES.txt
|
|
12
|
+
kanq_erp.egg-info/dependency_links.txt
|
|
13
|
+
kanq_erp.egg-info/entry_points.txt
|
|
14
|
+
kanq_erp.egg-info/requires.txt
|
|
15
|
+
kanq_erp.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kanq_erp
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "kanq_erp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
'drissionpage',
|
|
9
|
+
"python-dotenv>=1.2.1",
|
|
10
|
+
"typer>=0.21.1",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[project.scripts]
|
|
14
|
+
erp = "kanq_erp.erp:app"
|
|
15
|
+
|
|
16
|
+
[tool.setuptools]
|
|
17
|
+
packages = ['kanq_erp']
|
kanq_erp-0.1.0/setup.cfg
ADDED