OrcsRise commited on
Commit
b043e7b
·
1 Parent(s): 8bee326

Upload folder using huggingface_hub

Browse files
.gitignore ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /venv
2
+ /.idea
3
+ /.vscode
4
+ /index.bin
5
+ /texts.csv
6
+ /config.json
7
+ /temp
8
+ /upload
9
+ __pycache__
10
+ config.json
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.9
3
+
4
+ # Set the working directory to /app
5
+ WORKDIR /app
6
+
7
+ # Copy the requirements file
8
+ COPY requirements.txt .
9
+
10
+ # Install Dependencies
11
+ RUN pip3 install -r requirements.txt
12
+
13
+ # Copy the rest of the application's code
14
+ COPY . .
15
+
16
+ # Make port 7860 and 9531 available to the world outside this container
17
+ EXPOSE 7860
18
+ EXPOSE 9531
19
+
20
+ # Run the application when the container launches
21
+ CMD ["sh", "run.sh"]
__pycache__/ai.cpython-311.pyc ADDED
Binary file (13.7 kB). View file
 
__pycache__/api.cpython-311.pyc ADDED
Binary file (8.15 kB). View file
 
__pycache__/config.cpython-311.pyc ADDED
Binary file (3.65 kB). View file
 
__pycache__/console.cpython-311.pyc ADDED
Binary file (6.58 kB). View file
 
__pycache__/contents.cpython-311.pyc ADDED
Binary file (6.65 kB). View file
 
__pycache__/storage.cpython-311.pyc ADDED
Binary file (14.9 kB). View file
 
__pycache__/webui.cpython-311.pyc ADDED
Binary file (11.3 kB). View file
 
ai.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import openai
3
+ import tiktoken
4
+ from sklearn.feature_extraction.text import TfidfVectorizer
5
+ from sklearn.metrics.pairwise import cosine_similarity
6
+
7
+ from config import Config
8
+
9
+
10
+ class AI:
11
+ """The AI class."""
12
+
13
+ def __init__(self, cfg: Config):
14
+ openai.api_key = cfg.open_ai_key
15
+ openai.proxy = cfg.open_ai_proxy
16
+ self._chat_model = cfg.open_ai_chat_model
17
+ self._use_stream = cfg.use_stream
18
+ self._encoding = tiktoken.encoding_for_model('gpt-3.5-turbo')
19
+ self._language = cfg.language
20
+ self._temperature = cfg.temperature
21
+
22
+ def _chat_stream(self, messages: list[dict], use_stream: bool = None) -> str:
23
+ use_stream = use_stream if use_stream is not None else self._use_stream
24
+ response = openai.ChatCompletion.create(
25
+ temperature=self._temperature,
26
+ stream=use_stream,
27
+ model=self._chat_model,
28
+ messages=messages,
29
+ )
30
+ if use_stream:
31
+ data = ""
32
+ for chunk in response:
33
+ if chunk.choices[0].delta.get('content', None) is not None:
34
+ data += chunk.choices[0].delta.content
35
+ print(chunk.choices[0].delta.content, end='')
36
+ print()
37
+ return data.strip()
38
+ else:
39
+ print(response.choices[0].message.content.strip())
40
+ print(f"Total tokens used: {response.usage.total_tokens}, "
41
+ f"cost: ${response.usage.total_tokens / 1000 * 0.002}")
42
+ return response.choices[0].message.content.strip()
43
+
44
+ def _num_tokens_from_string(self, string: str) -> int:
45
+ """Returns the number of tokens in a text string."""
46
+ num_tokens = len(self._encoding.encode(string))
47
+ return num_tokens
48
+
49
+ def completion(self, query: str, context: list[str]):
50
+ """Create a completion."""
51
+ context = self._cut_texts(context)
52
+ print(f"Number of query fragments:{len(context)}")
53
+
54
+ text = "\n".join(f"{index}. {text}" for index, text in enumerate(context))
55
+ result = self._chat_stream([
56
+ {'role': 'system',
57
+ 'content': f'You are a helpful AI article assistant. '
58
+ f'The following are the relevant article content fragments found from the article. '
59
+ f'The relevance is sorted from high to low. '
60
+ f'You can only answer according to the following content:\n```\n{text}\n```\n'
61
+ f'You need to carefully consider your answer to ensure that it is based on the context. '
62
+ f'If the context does not mention the content or it is uncertain whether it is correct, '
63
+ f'please answer "Current context cannot provide effective information."'
64
+ f'You must use {self._language} to respond.'},
65
+ {'role': 'user', 'content': query},
66
+ ])
67
+ return result
68
+
69
+ def _cut_texts(self, context):
70
+ maximum = 4096 - 1024
71
+ for index, text in enumerate(context):
72
+ maximum -= self._num_tokens_from_string(text)
73
+ if maximum < 0:
74
+ context = context[:index + 1]
75
+ print(f"Exceeded maximum length, cut the first {index + 1} fragments")
76
+ break
77
+ return context
78
+
79
+ def get_keywords(self, query: str) -> str:
80
+ """Get keywords from the query."""
81
+ result = self._chat_stream([
82
+ {'role': 'user',
83
+ 'content': f'You need to extract keywords from the statement or question and '
84
+ f'return a series of keywords separated by commas.\ncontent: {query}\nkeywords: '},
85
+ ], use_stream=False)
86
+ return result
87
+
88
+ @staticmethod
89
+ def create_embedding(text: str) -> (str, list[float]):
90
+ """Create an embedding for the provided text."""
91
+ embedding = openai.Embedding.create(model="text-embedding-ada-002", input=text)
92
+ return text, embedding.data[0].embedding
93
+
94
+ def create_embeddings(self, texts: list[str]) -> (list[tuple[str, list[float]]], int):
95
+ """Create embeddings for the provided input."""
96
+ result = []
97
+ query_len = 0
98
+ start_index = 0
99
+ tokens = 0
100
+
101
+ def get_embedding(input_slice: list[str]):
102
+ embedding = openai.Embedding.create(model="text-embedding-ada-002", input=input_slice)
103
+ return [(txt, data.embedding) for txt, data in
104
+ zip(input_slice, embedding.data)], embedding.usage.total_tokens
105
+
106
+ for index, text in enumerate(texts):
107
+ query_len += self._num_tokens_from_string(text)
108
+ if query_len > 8192 - 1024:
109
+ ebd, tk = get_embedding(texts[start_index:index + 1])
110
+ print(f"Query fragments used tokens: {tk}, cost: ${tk / 1000 * 0.0004}")
111
+ query_len = 0
112
+ start_index = index + 1
113
+ tokens += tk
114
+ result.extend(ebd)
115
+
116
+ if query_len > 0:
117
+ ebd, tk = get_embedding(texts[start_index:])
118
+ print(f"Query fragments used tokens: {tk}, cost: ${tk / 1000 * 0.0004}")
119
+ tokens += tk
120
+ result.extend(ebd)
121
+ return result, tokens
122
+
123
+ def generate_summary(self, embeddings, num_candidates=3, use_sif=False):
124
+ """Generate a summary for the provided embeddings."""
125
+ avg_func = self._calc_paragraph_avg_embedding_with_sif if use_sif else self._calc_avg_embedding
126
+ avg_embedding = np.array(avg_func(embeddings))
127
+
128
+ paragraphs = [e[0] for e in embeddings]
129
+ embeddings = np.array([e[1] for e in embeddings])
130
+ # 计算每个段落与整个文本的相似度分数
131
+ # Calculate the similarity score between each paragraph and the entire text.
132
+ similarity_scores = cosine_similarity(embeddings, avg_embedding.reshape(1, -1)).flatten()
133
+
134
+ # 选择具有最高相似度分数的段落作为摘要的候选段落
135
+ # Select the paragraph with the highest similarity score as the candidate paragraph for the summary.
136
+ candidate_indices = np.argsort(similarity_scores)[::-1][:num_candidates]
137
+ candidate_paragraphs = [f"paragraph {i}: {paragraphs[i]}" for i in candidate_indices]
138
+
139
+ print("Calculation completed, start generating summary")
140
+
141
+ candidate_paragraphs = self._cut_texts(candidate_paragraphs)
142
+
143
+ text = "\n".join(f"{index}. {text}" for index, text in enumerate(candidate_paragraphs))
144
+ result = self._chat_stream([
145
+ {'role': 'system',
146
+ 'content': f'As a helpful AI article assistant, '
147
+ f'I have retrieved the following relevant text fragments from the article, '
148
+ f'sorted by relevance from high to low. '
149
+ f'You need to summarize the entire article from these fragments, '
150
+ f'and present the final result in {self._language}:\n\n{text}\n\n{self._language} summary:'},
151
+ ])
152
+ return result
153
+
154
+ @staticmethod
155
+ def _calc_avg_embedding(embeddings) -> list[float]:
156
+ # Calculate the average embedding for the entire text.
157
+ avg_embedding = np.zeros(len(embeddings[0][1]))
158
+ for emb in embeddings:
159
+ avg_embedding += np.array(emb[1])
160
+ avg_embedding /= len(embeddings)
161
+ return avg_embedding.tolist()
162
+
163
+ @staticmethod
164
+ def _calc_paragraph_avg_embedding_with_sif(paragraph_list) -> list[float]:
165
+ # calculate the SIF embedding for the entire text
166
+ alpha = 0.001
167
+ # calculate the total number of sentences
168
+ n_sentences = len(paragraph_list)
169
+
170
+ # calculate the total number of dimensions in the embeddings
171
+ n_dims = len(paragraph_list[0][1])
172
+
173
+ # calculate the IDF values for each word in the sentences
174
+ vectorizer = TfidfVectorizer(use_idf=True)
175
+ vectorizer.fit_transform([paragraph for paragraph, _ in paragraph_list])
176
+ idf = vectorizer.idf_
177
+
178
+ # calculate the SIF weights for each sentence
179
+ weights = np.zeros((n_sentences, n_dims))
180
+ for i, (sentence, embedding) in enumerate(paragraph_list):
181
+ sentence_words = sentence.split()
182
+ for word in sentence_words:
183
+ try:
184
+ word_index = vectorizer.vocabulary_[word]
185
+ word_idf = idf[word_index]
186
+ word_weight = alpha / (alpha + word_idf)
187
+ weights[i] += word_weight * (np.array(embedding) / np.max(embedding))
188
+ except KeyError:
189
+ pass
190
+
191
+ # calculate the weighted average of the sentence embeddings
192
+ weights_sum = np.sum(weights, axis=0)
193
+ weights_sum /= n_sentences
194
+ avg_embedding = np.zeros(n_dims)
195
+ for i, (sentence, embedding) in enumerate(paragraph_list):
196
+ avg_embedding += (np.array(embedding) / np.max(embedding)) - weights[i]
197
+ avg_embedding /= n_sentences
198
+
199
+ return avg_embedding.tolist()
api.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+
4
+ import uvicorn
5
+ import xxhash
6
+ from fastapi import FastAPI, UploadFile, File
7
+ from fastapi.exceptions import RequestValidationError
8
+ from pydantic import BaseModel
9
+ from starlette.exceptions import HTTPException
10
+ from starlette.requests import Request
11
+ from starlette.responses import JSONResponse
12
+
13
+ from ai import AI
14
+ from config import Config
15
+ from contents import web_crawler_newspaper, extract_text_from_txt, extract_text_from_docx, \
16
+ extract_text_from_pdf
17
+ from storage import Storage
18
+
19
+
20
+ def api(cfg: Config):
21
+ """Run the API."""
22
+
23
+ cfg.use_stream = False
24
+ ai = AI(cfg)
25
+
26
+ app = FastAPI()
27
+
28
+ class CrawlerUrlRequest(BaseModel):
29
+ url: str
30
+
31
+ @app.post("/crawler_url")
32
+ async def crawler_url(req: CrawlerUrlRequest):
33
+ """Crawler the URL."""
34
+ contents, lang = web_crawler_newspaper(req.url)
35
+ hash_id = xxhash.xxh3_128_hexdigest('\n'.join(contents))
36
+ tokens = _save_to_storage(contents, hash_id)
37
+ return {"code": 0, "msg": "ok", "data": {"uri": f"{hash_id}/{lang}", "tokens": tokens}}
38
+
39
+ def _save_to_storage(contents, hash_id):
40
+ storage = Storage.create_storage(cfg)
41
+ if storage.been_indexed(hash_id):
42
+ return 0
43
+ else:
44
+ embeddings, tokens = ai.create_embeddings(contents)
45
+ storage.add_all(embeddings, hash_id)
46
+ return tokens
47
+
48
+ @app.post("/upload_file")
49
+ async def create_upload_file(file: UploadFile = File(...)):
50
+ """Upload file."""
51
+ # save file to disk
52
+ file_name = file.filename
53
+ os.makedirs('./upload', exist_ok=True)
54
+ upload_path = os.path.join('./upload', file_name)
55
+ with open(upload_path, "wb") as buffer:
56
+ shutil.copyfileobj(file.file, buffer)
57
+ if file_name.endswith('.pdf'):
58
+ contents, lang = extract_text_from_pdf(upload_path)
59
+ elif file_name.endswith('.txt'):
60
+ contents, lang = extract_text_from_txt(upload_path)
61
+ elif file_name.endswith('.docx'):
62
+ contents, lang = extract_text_from_docx(upload_path)
63
+ else:
64
+ return {"code": 1, "msg": "not support", "data": {}}
65
+ hash_id = xxhash.xxh3_128_hexdigest('\n'.join(contents))
66
+ tokens = _save_to_storage(contents, hash_id)
67
+ os.remove(upload_path)
68
+ return {"code": 0, "msg": "ok", "data": {"uri": f"{hash_id}/{lang}", "tokens": tokens}}
69
+
70
+ @app.get("/summary")
71
+ async def summary(uri: str):
72
+ """Generate summary."""
73
+ hash_id, lang = uri.split('/')
74
+ storage = Storage.create_storage(cfg)
75
+ if not storage or not lang:
76
+ return {"code": 1, "msg": "not found", "data": {}}
77
+ s = ai.generate_summary(storage.get_all_embeddings(hash_id), num_candidates=100,
78
+ use_sif=lang not in ['zh', 'ja', 'ko', 'hi', 'ar', 'fa'])
79
+ return {"code": 0, "msg": "ok", "data": {"summary": s}}
80
+
81
+ class AnswerRequest(BaseModel):
82
+ uri: str
83
+ query: str
84
+
85
+ @app.get("/answer")
86
+ async def answer(req: AnswerRequest):
87
+ """Query."""
88
+ hash_id, lang = req.uri.split('/')
89
+ storage = Storage.create_storage(cfg)
90
+ if not storage or not lang:
91
+ return {"code": 1, "msg": "not found", "data": {}}
92
+ keywords = ai.get_keywords(req.query)
93
+ _, embedding = ai.create_embedding(keywords)
94
+ texts = storage.get_texts(embedding, hash_id)
95
+ s = ai.completion(req.query, texts)
96
+ return {"code": 0, "msg": "ok", "data": {"answer": s}}
97
+
98
+ @app.exception_handler(RequestValidationError)
99
+ async def validate_error_handler(request: Request, exc: RequestValidationError):
100
+ """Error handler."""
101
+ print("validate_error_handler: ", request.url, exc)
102
+ return JSONResponse(
103
+ status_code=400,
104
+ content={"code": 1, "msg": str(exc.errors()), "data": {}},
105
+ )
106
+
107
+ @app.exception_handler(HTTPException)
108
+ async def http_error_handler(request: Request, exc):
109
+ """Error handler."""
110
+ print("http error_handler: ", request.url, exc)
111
+ return JSONResponse(
112
+ status_code=400,
113
+ content={"code": 1, "msg": exc.detail, "data": {}},
114
+ )
115
+
116
+ # run the API
117
+ uvicorn.run(app, host=cfg.api_host, port=cfg.api_port)
config.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "open_ai_key": "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",
3
+ "temperature": 0.1,
4
+ "language": "English",
5
+ "open_ai_chat_model": "gpt-3.5-turbo-16k-0613",
6
+ "use_stream": false,
7
+ "use_postgres": false,
8
+ "index_path": "./temp",
9
+ "postgres_url": "postgresql://localhost:5432/mydb",
10
+ "mode": "webui",
11
+ "api_port": 9531,
12
+ "api_host": "localhost",
13
+ "webui_port": 7860,
14
+ "webui_host": "0.0.0.0"
15
+ }
config.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+
5
+ class Config:
6
+ def __init__(self):
7
+ config_path = os.path.join(os.path.dirname(__file__), 'config.json')
8
+ if not os.path.exists(config_path):
9
+ raise FileNotFoundError(f'config.json not found at {config_path}, '
10
+ f'please copy config.example.json to config.json and modify it.')
11
+ with open(config_path, 'r') as f:
12
+ self.config = json.load(f)
13
+ self.language = self.config.get('language', 'Chinese')
14
+ self.open_ai_key = self.config.get('open_ai_key')
15
+ self.open_ai_proxy = self.config.get('open_ai_proxy')
16
+ self.open_ai_chat_model = self.config.get('open_ai_chat_model', 'gpt-3.5-turbo')
17
+ if not self.open_ai_key:
18
+ raise ValueError('open_ai_key is not set')
19
+ self.temperature = self.config.get('temperature', 0.1)
20
+ if self.temperature < 0 or self.temperature > 1:
21
+ raise ValueError('temperature must be between 0 and 1, less is more conservative, more is more creative')
22
+ self.use_stream = self.config.get('use_stream', False)
23
+ self.use_postgres = self.config.get('use_postgres', False)
24
+ if not self.use_postgres:
25
+ self.index_path = self.config.get('index_path', './temp')
26
+ os.makedirs(self.index_path, exist_ok=True)
27
+ self.postgres_url = self.config.get('postgres_url')
28
+ if self.use_postgres and self.postgres_url is None:
29
+ raise ValueError('postgres_url is not set')
30
+ self.mode = self.config.get('mode', 'webui')
31
+ if self.mode not in ['console', 'api', 'webui']:
32
+ raise ValueError('mode must be console or api or webui')
33
+ self.api_port = self.config.get('api_port', 9531)
34
+ self.api_host = self.config.get('api_host', 'localhost')
35
+ self.webui_port = self.config.get('webui_port', 7860)
36
+ self.webui_host = self.config.get('webui_host', '0.0.0.0')
console.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xxhash
2
+
3
+ from ai import AI
4
+ from config import Config
5
+ from storage import Storage
6
+ from contents import *
7
+
8
+
9
+ def console(cfg: Config):
10
+ try:
11
+ while True:
12
+ if not _console(cfg):
13
+ return
14
+ except KeyboardInterrupt:
15
+ print("exit")
16
+
17
+
18
+ def _console(cfg: Config) -> bool:
19
+ """Run the console."""
20
+
21
+ contents, lang, identify = _get_contents()
22
+
23
+ print("The article has been retrieved, and the number of text fragments is:", len(contents))
24
+ for content in contents:
25
+ print('\t', content)
26
+
27
+ ai = AI(cfg)
28
+ storage = Storage.create_storage(cfg)
29
+
30
+ print("=====================================")
31
+ if storage.been_indexed(identify):
32
+ print("The article has already been indexed, so there is no need to index it again.")
33
+ print("=====================================")
34
+ else:
35
+ # 1. 对文章的每个段落生成embedding
36
+ # 1. Generate an embedding for each paragraph of the article.
37
+ embeddings, tokens = ai.create_embeddings(contents)
38
+ print(f"Embeddings have been created with {len(embeddings)} embeddings, using {tokens} tokens, "
39
+ f"costing ${tokens / 1000 * 0.0004}")
40
+
41
+ storage.add_all(embeddings, identify)
42
+ print("The embeddings have been saved.")
43
+ print("=====================================")
44
+
45
+ while True:
46
+ query = input("Please enter your query (/help to view commands):").strip()
47
+ if query.startswith("/"):
48
+ if query == "/quit":
49
+ return False
50
+ elif query == "/reset":
51
+ print("=====================================")
52
+ return True
53
+ elif query == "/summary":
54
+ # 生成embedding式摘要,根据不同的语言使用有基于SIF的加权平均或一般的直接求平均
55
+ # Generate an embedding-based summary, using weighted average based on SIF or direct average based on the language.
56
+ ai.generate_summary(storage.get_all_embeddings(identify), num_candidates=100,
57
+ use_sif=lang not in ['zh', 'ja', 'ko', 'hi', 'ar', 'fa'])
58
+ elif query == "/reindex":
59
+ # 重新索引,会清空数据库
60
+ # Re-index, which will clear the database.
61
+ storage.clear(identify)
62
+ embeddings, tokens = ai.create_embeddings(contents)
63
+ print(f"Embeddings have been created with {len(embeddings)} embeddings, using {tokens} tokens, "
64
+ f"costing ${tokens / 1000 * 0.0004}")
65
+
66
+ storage.add_all(embeddings, identify)
67
+ print("The embeddings have been saved.")
68
+ elif query == "/help":
69
+ print("Enter /summary to generate an embedding-based summary.")
70
+ print("Enter /reindex to re-index the article.")
71
+ print("Enter /reset to start over.")
72
+ print("Enter /quit to exit.")
73
+ print("Enter any other content for a query.")
74
+ else:
75
+ print("Invalid command.")
76
+ print("Enter /summary to generate an embedding-based summary.")
77
+ print("Enter /reindex to re-index the article.")
78
+ print("Enter /reset to start over.")
79
+ print("Enter /quit to exit.")
80
+ print("Enter any other content for a query.")
81
+ print("=====================================")
82
+ continue
83
+ else:
84
+ # 1. 生成关键词
85
+ # 1. Generate keywords.
86
+ print("Generate keywords.")
87
+ keywords = ai.get_keywords(query)
88
+ # 2. 对问题生成embedding
89
+ # 2. Generate an embedding for the question.
90
+ _, embedding = ai.create_embedding(keywords)
91
+ # 3. 从数据库中找到最相似的片段
92
+ # 3. Find the most similar fragments from the database.
93
+ texts = storage.get_texts(embedding, identify)
94
+ print("Related fragments found (first 5):")
95
+ for text in texts[:5]:
96
+ print('\t', text)
97
+ # 4. 把相关片段推给AI,AI会根据这些片段回答问题
98
+ # 4. Push the relevant fragments to the AI, which will answer the question based on these fragments.
99
+ ai.completion(query, texts)
100
+ print("=====================================")
101
+
102
+
103
+ def _get_contents() -> tuple[list[str], str, str]:
104
+ """Get the contents."""
105
+
106
+ while True:
107
+ try:
108
+ url = input("Please enter the link to the article or the file path of the PDF/TXT/DOCX document: ").strip()
109
+ if os.path.exists(url):
110
+ if url.endswith('.pdf'):
111
+ contents, data = extract_text_from_pdf(url)
112
+ elif url.endswith('.txt'):
113
+ contents, data = extract_text_from_txt(url)
114
+ elif url.endswith('.docx'):
115
+ contents, data = extract_text_from_docx(url)
116
+ else:
117
+ print("Unsupported file format.")
118
+ continue
119
+ else:
120
+ contents, data = web_crawler_newspaper(url)
121
+ if not contents:
122
+ print("Unable to retrieve the content of the article. Please enter the link to the article or "
123
+ "the file path of the PDF/TXT/DOCX document again.")
124
+ continue
125
+ return contents, data, xxhash.xxh3_128_hexdigest('\n'.join(contents))
126
+ except Exception as e:
127
+ print("Error:", e)
contents.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+
4
+ import PyPDF2
5
+ import docx
6
+ import readability
7
+ from langdetect import detect
8
+ from newspaper import fulltext, Article
9
+ from selenium import webdriver
10
+
11
+
12
+ def web_crawler_newspaper(url: str) -> tuple[list[str], str]:
13
+ """Run the web crawler."""
14
+ raw_html, lang = _get_raw_html(url)
15
+ try:
16
+ text = fulltext(raw_html, language=lang)
17
+ except:
18
+ article = Article(url)
19
+ article.download()
20
+ article.parse()
21
+ text = article.text
22
+ contents = [text.strip() for text in text.splitlines() if text.strip()]
23
+ return contents, lang
24
+
25
+
26
+ def _get_raw_html(url):
27
+ chrome_options = webdriver.ChromeOptions()
28
+ chrome_options.add_argument('--headless')
29
+ chrome_options.add_argument('--disable-gpu')
30
+ chrome_options.add_argument('--no-sandbox')
31
+ chrome_options.add_argument('--disable-dev-shm-usage')
32
+ chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
33
+ 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36')
34
+
35
+ with webdriver.Chrome(options=chrome_options) as driver:
36
+ driver.get(url)
37
+ print("Please wait for 5 seconds until the webpage finishes loading.")
38
+ time.sleep(5)
39
+ html = driver.page_source
40
+
41
+ doc = readability.Document(html)
42
+ html = doc.summary()
43
+ lang = detect(html)
44
+ return html, lang[0:2]
45
+
46
+
47
+ def extract_text_from_pdf(file_path: str) -> tuple[list[str], str]:
48
+ """Extract text content from a PDF file."""
49
+ with open(file_path, 'rb') as f:
50
+ pdf_reader = PyPDF2.PdfReader(f)
51
+ contents = []
52
+ for page in pdf_reader.pages:
53
+ page_text = page.extract_text().strip()
54
+ raw_text = [text.strip() for text in page_text.splitlines() if text.strip()]
55
+ new_text = ''
56
+ for text in raw_text:
57
+ new_text += text
58
+ if text[-1] in ['.', '!', '?', '。', '!', '?', '…', ';', ';', ':', ':', '”', '’', ')', '】', '》', '」',
59
+ '』', '〕', '〉', '》', '〗', '〞', '〟', '»', '"', "'", ')', ']', '}']:
60
+ contents.append(new_text)
61
+ new_text = ''
62
+ if new_text:
63
+ contents.append(new_text)
64
+ lang = detect('\n'.join(contents))
65
+ return contents, lang[0:2]
66
+
67
+
68
+ def extract_text_from_txt(file_path: str) -> tuple[list[str], str]:
69
+ """Extract text content from a TXT file."""
70
+ with open(file_path, 'r', encoding='utf-8') as f:
71
+ contents = [text.strip() for text in f.readlines() if text.strip()]
72
+ lang = detect('\n'.join(contents))
73
+ return contents, lang[0:2]
74
+
75
+
76
+ def extract_text_from_docx(file_path: str) -> tuple[list[str], str]:
77
+ """Extract text content from a DOCX file."""
78
+ document = docx.Document(file_path)
79
+ contents = [paragraph.text.strip() for paragraph in document.paragraphs if paragraph.text.strip()]
80
+ lang = detect('\n'.join(contents))
81
+ return contents, lang[0:2]
docker-compose.yml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: "3.9"
2
+
3
+ services:
4
+ chatweb:
5
+ build: .
6
+ ports:
7
+ - "9531:9531"
8
+ - "7860:7860"
9
+ volumes:
10
+ - ./config.json:/app/config.json
11
+ # - ./:/app
12
+ environment:
13
+ - OPENAI_API_KEY=${OPENAI_API_KEY}
example.ipynb ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "provenance": [],
7
+ "authorship_tag": "ABX9TyOKqfSVq+Brmr4ZM+kUh/HP",
8
+ "include_colab_link": true
9
+ },
10
+ "kernelspec": {
11
+ "name": "python3",
12
+ "display_name": "Python 3"
13
+ },
14
+ "language_info": {
15
+ "name": "python"
16
+ }
17
+ },
18
+ "cells": [
19
+ {
20
+ "cell_type": "markdown",
21
+ "metadata": {
22
+ "id": "view-in-github",
23
+ "colab_type": "text"
24
+ },
25
+ "source": [
26
+ "<a href=\"https://colab.research.google.com/github/SkywalkerDarren/chatWeb/blob/master/example.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "markdown",
31
+ "source": [
32
+ "把下面换成你自己的openai key,然后依次执行下列准备步骤\n",
33
+ "Please replace the following with your own OpenAI API key, and language, and then execute the following preparation steps in order:"
34
+ ],
35
+ "metadata": {
36
+ "id": "2rmPdzNs13ga"
37
+ }
38
+ },
39
+ {
40
+ "cell_type": "code",
41
+ "source": [
42
+ "open_ai_key = \"sk-xxxxxxxxxxxx\" # Your OpenAI API key\n",
43
+ "language = \"Chinese\" # Language of the chatbot"
44
+ ],
45
+ "metadata": {
46
+ "id": "roZqoNX0ubG5"
47
+ },
48
+ "execution_count": 8,
49
+ "outputs": []
50
+ },
51
+ {
52
+ "cell_type": "code",
53
+ "source": [
54
+ "%%shell\n",
55
+ "# Ubuntu no longer distributes chromium-browser outside of snap\n",
56
+ "#\n",
57
+ "# Proposed solution: https://askubuntu.com/questions/1204571/how-to-install-chromium-without-snap\n",
58
+ "\n",
59
+ "# Add debian buster\n",
60
+ "cat > /etc/apt/sources.list.d/debian.list <<'EOF'\n",
61
+ "deb [arch=amd64 signed-by=/usr/share/keyrings/debian-buster.gpg] http://deb.debian.org/debian buster main\n",
62
+ "deb [arch=amd64 signed-by=/usr/share/keyrings/debian-buster-updates.gpg] http://deb.debian.org/debian buster-updates main\n",
63
+ "deb [arch=amd64 signed-by=/usr/share/keyrings/debian-security-buster.gpg] http://deb.debian.org/debian-security buster/updates main\n",
64
+ "EOF\n",
65
+ "\n",
66
+ "# Add keys\n",
67
+ "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys DCC9EFBF77E11517\n",
68
+ "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138\n",
69
+ "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 112695A0E562B32A\n",
70
+ "\n",
71
+ "apt-key export 77E11517 | gpg --dearmour -o /usr/share/keyrings/debian-buster.gpg\n",
72
+ "apt-key export 22F3D138 | gpg --dearmour -o /usr/share/keyrings/debian-buster-updates.gpg\n",
73
+ "apt-key export E562B32A | gpg --dearmour -o /usr/share/keyrings/debian-security-buster.gpg\n",
74
+ "\n",
75
+ "# Prefer debian repo for chromium* packages only\n",
76
+ "# Note the double-blank lines between entries\n",
77
+ "cat > /etc/apt/preferences.d/chromium.pref << 'EOF'\n",
78
+ "Package: *\n",
79
+ "Pin: release a=eoan\n",
80
+ "Pin-Priority: 500\n",
81
+ "\n",
82
+ "\n",
83
+ "Package: *\n",
84
+ "Pin: origin \"deb.debian.org\"\n",
85
+ "Pin-Priority: 300\n",
86
+ "\n",
87
+ "\n",
88
+ "Package: chromium*\n",
89
+ "Pin: origin \"deb.debian.org\"\n",
90
+ "Pin-Priority: 700\n",
91
+ "EOF"
92
+ ],
93
+ "metadata": {
94
+ "id": "9HBoEHPFvaDv"
95
+ },
96
+ "execution_count": null,
97
+ "outputs": []
98
+ },
99
+ {
100
+ "cell_type": "code",
101
+ "source": [
102
+ "!apt-get update\n",
103
+ "!apt-get install chromium chromium-driver\n",
104
+ "!git clone https://github.com/SkywalkerDarren/chatWeb.git\n",
105
+ "%cd chatWeb\n",
106
+ "!pip3 install -r requirements.txt"
107
+ ],
108
+ "metadata": {
109
+ "id": "71znqup2wrt-"
110
+ },
111
+ "execution_count": null,
112
+ "outputs": []
113
+ },
114
+ {
115
+ "cell_type": "code",
116
+ "source": [
117
+ "import json\n",
118
+ "\n",
119
+ "with open('config.example.json', 'r') as f:\n",
120
+ " config = json.load(f)\n",
121
+ "\n",
122
+ "config['open_ai_key'] = open_ai_key\n",
123
+ "config['language'] = language\n",
124
+ "\n",
125
+ "with open('config.json', 'w') as f:\n",
126
+ " json.dump(config, f)"
127
+ ],
128
+ "metadata": {
129
+ "id": "b5kT-S5rt1e6"
130
+ },
131
+ "execution_count": null,
132
+ "outputs": []
133
+ },
134
+ {
135
+ "cell_type": "markdown",
136
+ "source": [
137
+ "以上是准备步骤,准备完后运行下面这条命令即可,quit以后也可以重复运行\n",
138
+ "The above are preparation steps, run the following command after preparation, and you can also run it again after /quit."
139
+ ],
140
+ "metadata": {
141
+ "id": "yfJMbmUL1Vfp"
142
+ }
143
+ },
144
+ {
145
+ "cell_type": "code",
146
+ "source": [
147
+ "!python3 main.py"
148
+ ],
149
+ "metadata": {
150
+ "id": "gQBKF8cxu3AY"
151
+ },
152
+ "execution_count": null,
153
+ "outputs": []
154
+ }
155
+ ]
156
+ }
main.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from api import api
5
+ from config import Config
6
+ from console import console
7
+ from webui import webui
8
+
9
+
10
+ def run():
11
+ """Run the program."""
12
+ cfg = Config()
13
+
14
+ mode = cfg.mode
15
+ if mode == 'console':
16
+ console(cfg)
17
+ elif mode == 'api':
18
+ api(cfg)
19
+ elif mode == 'webui':
20
+ webui(cfg)
21
+ else:
22
+ raise ValueError('mode must be console or api')
23
+
24
+
25
+ if __name__ == '__main__':
26
+ run()
readme.md ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Smart_Pdf_Reader
3
+ app_file: webui.py
4
+ sdk: gradio
5
+ sdk_version: 3.34.0
6
+ ---
7
+ # ChatWeb
8
+
9
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SkywalkerDarren/chatWeb/blob/master/example.ipynb)
10
+
11
+ [English Doc](readme.md)
12
+ [中文文档](readme.zh.md)
13
+
14
+ ChatWeb can crawl any webpage or extract text from PDF, DOCX, TXT files, and generate an embedded summary.
15
+ It can also answer your questions based on the content of the text.
16
+ It is implemented using the chatAPI and embeddingAPI based on gpt3.5, as well as a vector database.
17
+
18
+ # Basic Principle
19
+ The basic principle is similar to existing projects such as chatPDF and automated customer service AI.
20
+
21
+ Crawl web pages
22
+ Extract text content
23
+ Use GPT3.5's embedding API to generate vectors for each paragraph
24
+ Calculate the similarity score between each paragraph's vector and the entire text's vector to generate a summary
25
+ Store the vector-text mapping in a vector database
26
+ Generate keywords from user input
27
+ Generate a vector from the keywords
28
+ Use the vector database to perform a nearest neighbor search and return a list of the most similar texts
29
+ Use GPT3.5's chat API to design a prompt that answers the user's question based on the most similar texts in the list.
30
+ The idea is to extract relevant content from a large amount of text and then answer questions based on that content, which can achieve a similar effect to breaking through token limits.
31
+
32
+ An improvement was made to generate vectors based on keywords rather than the user's question, which increases the accuracy of searching for relevant texts.
33
+
34
+ # Getting Started
35
+
36
+ ## Manual installation:
37
+
38
+ - Install Python3
39
+ - Download this repository by running `git clone https://github.com/SkywalkerDarren/chatWeb.git`
40
+ - Navigate to the directory by running `cd chatWeb`
41
+ - Copy `config.example.json` to `config.json`
42
+ - Edit `config.json` and set `open_ai_key` to your OpenAI API key
43
+ - Install dependencies by running `pip3 install -r requirements.txt`
44
+ - Start the application by running `python3 main.py`
45
+
46
+ ## Docker:
47
+ if you prefer, you can also run this project using docker:
48
+
49
+ - build the container using `docker-compose build` (only needed once when you are not planning to contibute to this repo)
50
+ - copy `config.example.json` to `config.json` and set all the needed stuff. The example config is already fine for running with docker, no need to change anything there, if you don't have the OPEN_AI_KEY in your env variables you can set it here too, or later if you run this app.
51
+ - run the container: `docker-compose up"
52
+ - open the application in browser: `http://localhost:7860`
53
+
54
+ ## Set language
55
+
56
+ - Edit `config.json`, set `language` to `English` or other language
57
+
58
+ ## Mode Selection
59
+
60
+ - Edit `config.json` and set `mode` to `console`, `api`, or `webui` to choose the startup mode.
61
+ - In `console` mode, type `/help` to view commands.
62
+ - In `api` mode, an API service can be provided to the outside world. `api_port` and `api_host` can be set in `config.json`.
63
+ - In `webui` mode, a web user interface service can be provided. `webui_port` can be set in `config.json`, defaulting to `http://127.0.0.1:7860`.
64
+
65
+ ## Stream Mode
66
+
67
+ - Edit `config.json` and set `use_stream` to `true`.
68
+
69
+ ## Setting the Temperature
70
+
71
+ - Edit `config.json` and set `temperature` to a value between 0 and 1.
72
+ - The smaller the value, the more conservative and stable the response will be. The larger the value, the more daring the response may be, possibly resulting in "hallucinations."
73
+
74
+ ## OpenAI Proxy Settings
75
+
76
+ - Edit `config.json` and add `open_ai_proxy` for your proxy address, for example:
77
+ ```
78
+ "open_ai_proxy": {
79
+ "http": "socks5://127.0.0.1:1081",
80
+ "https": "socks5://127.0.0.1:1081"
81
+ }
82
+ ```
83
+
84
+ ## Install PostgreSQL (Optional)
85
+
86
+ - Edit `config.json` and set `use_postgres` to `true`.
87
+ - Install PostgreSQL.
88
+ - The default SQL address is `postgresql://localhost:5432/mydb`, or you can set it in `config.json`.
89
+ - Install the pgvector plugin.
90
+
91
+ Compile and install the extension (support Postgres 11+).
92
+
93
+ ```bash
94
+ git clone --branch v0.4.0 https://github.com/pgvector/pgvector.git
95
+ cd pgvector
96
+ make
97
+ make install # may need sudo
98
+ ```
99
+ Then load it in the database you want to use it in
100
+
101
+ ```postgresql
102
+ CREATE EXTENSION vector;
103
+ ```
104
+
105
+ - Install dependency with pip: `pip3 install psycopg2`
106
+
107
+ # Example
108
+ ```txt
109
+ Please enter the link to the article or the file path of the PDF/TXT/DOCX document: https://gutenberg.ca/ebooks/hemingwaye-oldmanandthesea/hemingwaye-oldmanandthesea-00-e.html
110
+ Please wait for 10 seconds until the webpage finishes loading.
111
+ The article has been retrieved, and the number of text fragments is: 663
112
+ ...
113
+ =====================================
114
+ Query fragments used tokens: 7219, cost: $0.0028876
115
+ Query fragments used tokens: 7250, cost: $0.0029000000000000002
116
+ Query fragments used tokens: 7188, cost: $0.0028752
117
+ Query fragments used tokens: 7177, cost: $0.0028708
118
+ Query fragments used tokens: 2378, cost: $0.0009512000000000001
119
+ Embeddings have been created with 663 embeddings, using 31212 tokens, costing $0.0124848
120
+ The embeddings have been saved.
121
+ =====================================
122
+ Please enter your query (/help to view commands):
123
+ ```
124
+
125
+ # TODO
126
+ - [x] Support for pdf/txt/docx files
127
+ - [x] Support for in-memory storage without a database (faiss)
128
+ - [x] Support for Stream
129
+ - [x] Support for API
130
+ - [x] Support for proxies
131
+ - [x] Add Colab support
132
+ - [x] Add language support
133
+ - [x] Support for temperature
134
+ - [x] Support for webui
135
+ - [ ] Other features that have not been thought of yet
136
+
137
+ # Star History
138
+
139
+ ![](https://api.star-history.com/svg?repos=SkywalkerDarren/chatWeb)
readme.zh.md ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ChatWeb
2
+
3
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SkywalkerDarren/chatWeb/blob/master/example.ipynb)
4
+
5
+ ChatWeb可以爬取任意网页或PDF,DOCX,TXT文件并提取正文,可以生成嵌入式概要,可以根据正文内容回答你的问题。
6
+ 基于gpt3.5的chatAPI和embeddingAPI,以及向量数据库实现。
7
+
8
+ # 基本原理
9
+
10
+ 基本类似于现有的chatPDF,自动化客服AI等项目的原理。
11
+
12
+ 1. 爬取网页
13
+ 2. 提取正文
14
+ 3. 对于每一段落,使用gpt3.5的embeddingAPI生成向量
15
+ 4. 每一段落的向量和全文向量做计算,生成概要
16
+ 5. 将向量和文本对应关系存入向量数据库
17
+ 6. 对于用户输入,生成关键词
18
+ 7. 对关键词生成向量
19
+ 8. 使用向量数据库进行最近邻搜索,返回最相似的文本列表
20
+ 9. 使用gpt3.5的chatAPI,设计prompt,使其基于最相似的文本列表进行回答
21
+
22
+ 新增的使用关键词生成向量相比直接使用问题生成向量,提高了对相关文本的搜索准确度
23
+
24
+ 就是先把大量文本中提取相关内容,再进行回答,最终可以达到类似突破token限制的效果
25
+
26
+ # 准备开始
27
+
28
+ - 安装python3
29
+
30
+ - 下载本仓库`git clone https://github.com/SkywalkerDarren/chatWeb.git`
31
+
32
+ - 进入目录`cd chatWeb`
33
+
34
+ - 复制`config.example.json`为`config.json`
35
+
36
+ - 编辑`config.json`, 设置`open_ai_key`为你的openai的api key
37
+
38
+ - 安装依赖
39
+
40
+ ```
41
+ pip3 install -r requirements.txt
42
+ ```
43
+
44
+ - 运行
45
+
46
+ ```
47
+ python3 main.py
48
+ ```
49
+
50
+ ## 模式选择
51
+
52
+ - 编辑`config.json`, 设置`mode`为`console`, `api`或`webui`作为选择启动模式。
53
+ - `console`模式下,输入`/help`查看指令
54
+ - `api`模式下,可对外提供api服务,在`config.json`中可设置`api_port`和`api_host`
55
+ - `webui`模式下,可提供webui服务,在`config.json`中可设置`webui_port`,默认为`http://127.0.0.1:7860`
56
+
57
+ ## Stream模式
58
+
59
+ - 编辑`config.json`, 设置`use_stream`为`true`
60
+
61
+ ## temperature设置
62
+
63
+ - 编辑`config.json`, 设置`temperature`为0-1之间的数值
64
+ - 数值越小,回答越保守稳定,数值越大,回答越大胆,可能导致出现“幻觉”
65
+
66
+ ## OpenAI代理设置
67
+
68
+ - 编辑`config.json`, 添加`open_ai_proxy`为你的代理地址,如:
69
+ ```
70
+ "open_ai_proxy": {
71
+ "http": "socks5://127.0.0.1:1081",
72
+ "https": "socks5://127.0.0.1:1081"
73
+ }
74
+ ```
75
+
76
+ ## 安装postgresql(可选)
77
+
78
+ - 编辑`config.json`, 设置`use_postgres`为`true`
79
+
80
+ - 安装postgresql
81
+ - 默认的sql地址: `postgresql://localhost:5432/mydb`或在`config.json`中设置
82
+ - 安装pgvector插件
83
+
84
+ 编译并安装扩展(支持Postgres 11+)
85
+
86
+ ```bash
87
+ git clone --branch v0.4.0 https://github.com/pgvector/pgvector.git
88
+ cd pgvector
89
+ make
90
+ make install # may need sudo
91
+ ```
92
+
93
+ 然后在您要使用它的数据库中加载它
94
+
95
+ ```postgresql
96
+ CREATE EXTENSION vector;
97
+ ```
98
+
99
+ - pip安装依赖`pip3 install psycopg2`
100
+
101
+
102
+ # Example
103
+ ```txt
104
+ Please enter the link to the article or the file path of the PDF/TXT/DOCX document: https://gutenberg.ca/ebooks/hemingwaye-oldmanandthesea/hemingwaye-oldmanandthesea-00-e.html
105
+ Please wait for 10 seconds until the webpage finishes loading.
106
+ The article has been retrieved, and the number of text fragments is: 663
107
+ ...
108
+ =====================================
109
+ Query fragments used tokens: 7219, cost: $0.0028876
110
+ Query fragments used tokens: 7250, cost: $0.0029000000000000002
111
+ Query fragments used tokens: 7188, cost: $0.0028752
112
+ Query fragments used tokens: 7177, cost: $0.0028708
113
+ Query fragments used tokens: 2378, cost: $0.0009512000000000001
114
+ Embeddings have been created with 663 embeddings, using 31212 tokens, costing $0.0124848
115
+ The embeddings have been saved.
116
+ =====================================
117
+ Please enter your query (/help to view commands):
118
+ ```
119
+
120
+ # TODO
121
+ - [x] 支持pdf/txt/docx文件
122
+ - [x] 支持免数据库纯内存(faiss)
123
+ - [x] 支持Stream
124
+ - [x] 支持API
125
+ - [x] 支持代理
126
+ - [x] 添加colab
127
+ - [x] 添加语言支持
128
+ - [x] 支持temperature
129
+ - [x] 支持webui
130
+ - [ ] 其他还没想到的
requirements.txt ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiohttp
2
+ aiosignal
3
+ anyio
4
+ async-generator
5
+ async-timeout
6
+ attrs
7
+ beautifulsoup4
8
+ certifi
9
+ cffi
10
+ chardet
11
+ charset-normalizer
12
+ click
13
+ colorama
14
+ cssselect
15
+ exceptiongroup
16
+ faiss-cpu
17
+ fastapi
18
+ feedfinder2
19
+ feedparser
20
+ filelock
21
+ frozenlist
22
+ greenlet
23
+ h11
24
+ httptools
25
+ idna
26
+ jieba3k
27
+ joblib
28
+ langdetect
29
+ lxml
30
+ multidict
31
+ newspaper3k
32
+ nltk
33
+ numpy
34
+ openai
35
+ outcome
36
+ pandas
37
+ pgvector
38
+ Pillow
39
+ pycparser
40
+ pydantic
41
+ PyPDF2
42
+ PySocks
43
+ python-dateutil
44
+ python-docx
45
+ python-dotenv
46
+ python-multipart
47
+ pytz
48
+ PyYAML
49
+ readability-lxml
50
+ regex
51
+ requests
52
+ requests-file
53
+ scikit-learn
54
+ scipy
55
+ selenium
56
+ sgmllib3k
57
+ six
58
+ sniffio
59
+ sortedcontainers
60
+ soupsieve
61
+ SQLAlchemy
62
+ starlette
63
+ threadpoolctl
64
+ tiktoken
65
+ tinysegmenter
66
+ tldextract
67
+ tqdm
68
+ trio
69
+ trio-websocket
70
+ typing_extensions
71
+ urllib3
72
+ uvicorn
73
+ watchfiles
74
+ websockets
75
+ wsproto
76
+ xxhash
77
+ yarl
78
+ gradio
79
+ psycopg2
run.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ echo "Starting..."
4
+ python3 main.py
storage.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path
2
+ from abc import ABC, abstractmethod
3
+
4
+ import faiss
5
+ import numpy as np
6
+ import pandas as pd
7
+ from pgvector.sqlalchemy import Vector
8
+ from sqlalchemy import create_engine, Column, Integer, String
9
+ from sqlalchemy.orm import sessionmaker, declarative_base
10
+
11
+ from config import Config
12
+
13
+ Base = declarative_base()
14
+
15
+
16
+ class Storage(ABC):
17
+ """Abstract Storage class."""
18
+
19
+ # factory method
20
+ @staticmethod
21
+ def create_storage(cfg: Config) -> 'Storage':
22
+ """Create a storage object."""
23
+ if cfg.use_postgres:
24
+ return _PostgresStorage(cfg)
25
+ else:
26
+ return _IndexStorage(cfg)
27
+
28
+ @abstractmethod
29
+ def add_all(self, embeddings: list[tuple[str, list[float]]], name: str):
30
+ """Add multiple embeddings."""
31
+ pass
32
+
33
+ @abstractmethod
34
+ def get_texts(self, embedding: list[float], name: str, limit=100) -> list[str]:
35
+ """Get the text for the provided embedding."""
36
+ pass
37
+
38
+ @abstractmethod
39
+ def get_all_embeddings(self, name: str):
40
+ """Get all embeddings."""
41
+ pass
42
+
43
+ @abstractmethod
44
+ def clear(self, name: str):
45
+ """Clear the database."""
46
+ pass
47
+
48
+ @abstractmethod
49
+ def been_indexed(self, name: str) -> bool:
50
+ """Check if the database has been indexed."""
51
+ pass
52
+
53
+
54
+ class _IndexStorage(Storage):
55
+ """IndexStorage class."""
56
+
57
+ def __init__(self, cfg: Config):
58
+ """Initialize the storage."""
59
+ self._cfg = cfg
60
+
61
+ def add_all(self, embeddings: list[tuple[str, list[float]]], name):
62
+ """Add multiple embeddings."""
63
+ texts, index = self._load(name)
64
+ ids = np.array([len(texts) + i for i, _ in enumerate(embeddings)])
65
+ texts = pd.concat([texts, pd.DataFrame(
66
+ {'index': len(texts) + i, 'text': text} for i, (text, _) in enumerate(embeddings))])
67
+ array = np.array([emb for text, emb in embeddings])
68
+ index.add_with_ids(array, ids)
69
+ self._save(texts, index, name)
70
+
71
+ def get_texts(self, embedding: list[float], name: str, limit=100) -> list[str]:
72
+ """Get the text for the provided embedding."""
73
+ texts, index = self._load(name)
74
+ _, indexs = index.search(np.array([embedding]), limit)
75
+ indexs = [i for i in indexs[0] if i >= 0]
76
+ return [f'paragraph {p}: {t}' for _, p, t in texts.iloc[indexs].values]
77
+
78
+ def get_all_embeddings(self, name: str):
79
+ texts, index = self._load(name)
80
+ texts = texts.text.tolist()
81
+ embeddings = index.reconstruct_n(0, len(texts))
82
+ return list(zip(texts, embeddings))
83
+
84
+ def clear(self, name: str):
85
+ """Clear the database."""
86
+ self._delete(name)
87
+
88
+ def been_indexed(self, name: str) -> bool:
89
+ return os.path.exists(os.path.join(self._cfg.index_path, f'{name}.csv')) and os.path.exists(
90
+ os.path.join(self._cfg.index_path, f'{name}.bin'))
91
+
92
+ def _save(self, texts, index, name: str):
93
+ texts.to_csv(os.path.join(self._cfg.index_path, f'{name}.csv'))
94
+ faiss.write_index(index, os.path.join(self._cfg.index_path, f'{name}.bin'))
95
+
96
+ def _load(self, name: str):
97
+ if self.been_indexed(name):
98
+ texts = pd.read_csv(os.path.join(self._cfg.index_path, f'{name}.csv'))
99
+ index = faiss.read_index(os.path.join(self._cfg.index_path, f'{name}.bin'))
100
+ else:
101
+ texts = pd.DataFrame(columns=['index', 'text'])
102
+ # IDMap2 with Flat
103
+ index = faiss.index_factory(1536, "IDMap2,Flat", faiss.METRIC_INNER_PRODUCT)
104
+ return texts, index
105
+
106
+ def _delete(self, name: str):
107
+ try:
108
+ os.remove(os.path.join(self._cfg.index_path, f'{name}.csv'))
109
+ os.remove(os.path.join(self._cfg.index_path, f'{name}.bin'))
110
+ except FileNotFoundError:
111
+ pass
112
+
113
+
114
+ def singleton(cls):
115
+ instances = {}
116
+
117
+ def get_instance(cfg):
118
+ if cls not in instances:
119
+ instances[cls] = cls(cfg)
120
+ return instances[cls]
121
+
122
+ return get_instance
123
+
124
+
125
+ @singleton
126
+ class _PostgresStorage(Storage):
127
+ """PostgresStorage class."""
128
+
129
+ def __init__(self, cfg: Config):
130
+ """Initialize the storage."""
131
+ self._postgresql = cfg.postgres_url
132
+ self._engine = create_engine(self._postgresql)
133
+ Base.metadata.create_all(self._engine)
134
+ session = sessionmaker(bind=self._engine)
135
+ self._session = session()
136
+
137
+ def add_all(self, embeddings: list[tuple[str, list[float]]], name: str):
138
+ """Add multiple embeddings."""
139
+ data = [self.EmbeddingEntity(text=text, embedding=embedding, name=name) for text, embedding in embeddings]
140
+ self._session.add_all(data)
141
+ self._session.commit()
142
+
143
+ def get_texts(self, embedding: list[float], name: str, limit=100) -> list[str]:
144
+ """Get the text for the provided embedding."""
145
+ result = self._session.query(self.EmbeddingEntity).where(self.EmbeddingEntity.name == name).order_by(
146
+ self.EmbeddingEntity.embedding.cosine_distance(embedding)).limit(limit).all()
147
+ return [f'paragraph {s.id}: {s.text}' for s in result]
148
+
149
+ def get_all_embeddings(self, name: str):
150
+ """Get all embeddings."""
151
+ result = self._session.query(self.EmbeddingEntity).where(self.EmbeddingEntity.name == name).all()
152
+ return [(s.text, s.embedding) for s in result]
153
+
154
+ def clear(self, name: str):
155
+ """Clear the database."""
156
+ self._session.query(self.EmbeddingEntity).where(self.EmbeddingEntity.name == name).delete()
157
+ self._session.commit()
158
+
159
+ def been_indexed(self, name: str) -> bool:
160
+ return self._session.query(self.EmbeddingEntity).filter_by(name=name).first() is not None
161
+
162
+ def __del__(self):
163
+ """Close the session."""
164
+ self._session.close()
165
+
166
+ class EmbeddingEntity(Base):
167
+ __tablename__ = 'embedding'
168
+ id = Column(Integer, primary_key=True)
169
+ name = Column(String)
170
+ text = Column(String)
171
+ embedding = Column(Vector(1536))
temp/ce31c2a1e1d78b8529d970348f6b293e.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6a6ee58765092913c3b5631e27b87107ff74272e9f7c2f004c99e3a035f2e68a
3
+ size 572226
temp/ce31c2a1e1d78b8529d970348f6b293e.csv ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ,index,text
2
+ 0,0,| 1Namık Kemal (1840-1888)
3
+ 1,1,"Şair, gazeteci ve düşünce adamı."
4
+ 2,2,"Türk edebiyatı ve düşünce hayatında “vatan ve hürriyet şairi” olarak tanınan Namık Kemal 26 Şevval 1256 (21 Aralık1840)’da Tekirdağ’da doğdu. Asıl adı Mehmet Kemal’dir. Babası Meclis-i Maliye ve Esham Müdürlüğünden sonra birsüre Sultan II. Abdülhamid’in Müneccimbaşılığını yapan Mustafa Âsım Bey, annesi ise, Koniçe eşrafından AbdüllâtifPaşa’nın kızı Fatma Zehra Hanım’dır. Sekiz yaşında annesini kaybeden Namık Kemal’in çocukluk ve ilk gençlik çağıdedesi Abdüllâtif Paşa’nın yanında geçti. Abdüllâtif Paşa kaymakam ve vali olarak görev yaptığı her yere torunu NamıkKemal’i de götürdü. Dedesinin Kütahya kaymakamlığından azledilerek İstanbul’a döndüğü sırada üç ay Bayezid ve yedisekiz ay kadar da Valide Mektebi’nde öğrenim görebildi. Düzenli bir okul eğitimi alamayan Namık Kemal, aldığı özeldersler ve kendi çabası ile kendini yetiştirmeye çalıştı. Dedesi Abdüllâtif Paşa Mart 1853’te Kars’a kaymakam olaraktayin edildi. On üç yaşındaki Namık Kemal’in ilk fikrî uyanışı Kars’ta oldu. Burada müderrisliğinin yanı sıra şairliği ile detanınan Vâizzâde Mehmed Seyyid Efendi’den tasavvuf ve edebiyat öğrendi. Şiir yazma denemeleri ve ilk mısralarıburada oluştu. Ayrıca Kars’ta binicilik, cirit ve av sporlarını yapma fırsatı buldu. Yıllar sonra Cezmi ve Vatan YahutSilistre adlı eserlerine yansıyacak olan Kırım Savaşı’nı, bulunduğu serhat şehri Kars’ta dramatik yönleriyle birlikteyaşadı. Millî duyguları yine bu vatansever çevrede gelişti. Dedesi Abdüllâtif Paşa, 1854 Temmuzunun sonlarındagörevinden azledildi ve tekrar İstanbul’a dönüldü. Babasına da kavuşan Namık Kemal İstanbul’da kaldığı on aylıksürede Osmanlı tarihi okudu, Arapça ve Farsça derslere devam etti. Dedesi, Mayıs 1855’te Sofya’ya kaymakam olaraktayin edildiği sırada on beş yaşında bulunan Namık Kemal’in asıl fikrî gelişmesi ve şiire yönelmesi dedesi ile birliktebulunduğu Sofya’da oldu. O, “birbiri ardınca yazdığı gazeller, nazîreler, Kerbelâ mersiyeleriyle” adından söz ettirmeyebaşladı. Sofya’da iken birikmiş bir hayli şiirini gören şair Binbaşı Eşref Bey, bir mahlasnâme tanzim ederek ona“Nâmık” mahlasını verdi. Burada aynı zamanda tasavvufa yönelen Namık Kemal, Hz. Ali ve Mevlevî’lere muhabbetbesledi. Kerbelâ mersiyeleri ve Mevlevî ilhamı ile birçok şiir yazdı. 1856’da Sofya’da Niş Kadısı Mustafa RagıpEfendi’nin kızı Nesîme Hanım ile evlendi. Abdüllâtif Paşa’nın 1856 Eylülünde azledilmesi üzerine Namık Kemal ve ailesiİstanbul’a döndü. Büyük bir sanat hevesi içerisinde olan Namık Kemal, İstanbul’da geniş bir fikir ve siyaset çevresibuldu. Kendisini geliştirmek için, devrin büyük âlimlerinden tefsir, hadis, fıkıh, tasavvuf, Arap ve Acem edebiyatıdersleri aldı. Hâriciye Nezâreti Tercüme Odası’nda çalışma hayatına başladı. Bu iş çevresinde Şehnâme-i Osmanî adlıküçük bir şiir kitabının yazarı Tahir Ömerzâde Yusuf Hâlis Efendi, Sadullah Paşa, Âyetullah, Kânî Paşazade Rifat,Recaizâde Celâl Beyler gibi Batı’yı iyi tanıyan fen ve terakki hayranı kimseleri tanıdı. Tercüme Odası’na devam ettiğisırada Leskofçalı Galib ve Hersekli Ârif Hikmet’le yakın temas kurdu. Bunlar arasında bilhassa Divan şiirindeki ifadekalıplarını kıran ve yeni bir çığırın açılmasında rol oynayan Leskofçalı Galib’e hayranlığı arttı. Divan tarzı şiirlerini onunetkisinde kalarak yazdı. 1861 yılında eski ve yeni nesilden şairlerin bir araya gelerek oluşturdukları Encümen-iŞu’araya o sırada Emtia Gümrüğü Tahrîrat Kalemi Başkâtip Muavini olarak görev yapan Namık Kemal de katıldı."
5
+ 3,3,Tercüme Odası o zaman için Bâbıâli’nin Batı’ya açılan bir penceresiydi. Bazılarınca bir “ilimler encümeni” bazılarıncada “Babıâli’nin muhalif fırkası” diye nitelendirilen Tercüme Odası’nın Namık Kemal’in üzerindeki etkisi büyük oldu.
6
+ 4,4,"Namık Kemal, 1862’de Tasvîr-i Efkâr ’ı yayımlamaya başlayan Şinasî ile tanıştı. Şinasî, tanıştıkları ilk gün onaFransızcasını ilerletmesini tavsiye etti. Namık Kemal’in Fransızcadan ilk tercümesini, fikirlerini benimsediğiMontesquieu’nun eserlerinden bazı parçalar oluşturdu. Namık Kemal imzalı ilk tercüme yazıları 1273 RamazanındaMir’at ’ta yayımlandı. Sosyal ve siyasî fikirlerini benimsediği, “yenilikçi” saydığı Şinasî’nin gazetesi Tasvîr-i Efkâr ’da"
7
+ 5,5,"| 2yazılarını neşretmeye başladı. Gazetecilik onun hareket alanını genişletti. Yazdığı makaleleri sayesinde hızla şöhretiarttı. Gazete yazılarında yeni bir üslûp ve nesir tarzına yöneldi. Coşkun bir mizaca sahip olan Namık Kemal’in, Şinasî’yitanıdıktan sonra şiirinin hem konusu hem de içeriği değişime uğradı. Şinasî’nin 1865 baharında gizlice Paris’egidişinden sonra Tasvîr-i Efkâr’ı Namık Kemal çıkarmaya devam etti. Gazetede önceleri eğitim, sağlık, şehir işleri,maliyenin ıslahı, bazı sosyal ve millî meseleler ile ilgili makalelere yer verdi. Kısa sürede aydın zümrenin tanıdığı veilgiyle takip ettiği biri oldu. Daha sonra yazdığı yazılarında, 1866’da çıkan Girit İsyanı’nın “amansız surette”"
8
+ 6,6,"bastırılması, Tepebaşı kahvelerinde Rumca şarkı söylenmesi, muzır neşriyat konuları gibi içte ve dışta yaşananolayların sorumlularını ve uygulanan siyaseti eleştirdi. Bu tür yazılardan sonra gazete siyasî bir hüviyet de kazanmışoldu. Tasvîr-i Efkâr ’da 1866 yılında yayımladığı “yeni edebiyatın ilk beyannamesi” sayılabilecek “Lisân-ı Osmanî’ninEdebiyatı Hakkında Bazı Mülâhazâtı Şâmildir” adlı makalesinde, Türk dili ve edebiyatının meselelerini cesurca veetraflıca ele aldı. “Ramazan Mektubu” adlı ilk denilebilecek mahallî röportaj örneği ile de değişen şehir hayatını,gözlemlerine dayanarak yansıtmaya çalıştı. Namık Kemal, 1866 yılından itibaren çeşitli vesilelerle yazdığı yazılarındaTürkçenin hayatımızdaki yeri üzerinde durdu. 1865 yılında daha sonra Yeni Osmanlılar Cemiyeti ismini alacak olan“İttifâk-ı Hamiyyet” adlı gizlice oluşan cemiyete girdi. Bu gizli cemiyetin gayesi, Sadrazam Âli Paşa’nın ağır, ezicipolitikalarına son vermek ve ülkeye parlamento esasına dayalı Meşrutiyet idaresini getirmekti. Bu cemiyet vasıtasıylaVeliaht Murad Efendi ve Şehzade II. Abdülhamid ile tanıştı ve onlarla dostluğunu ilerletti. Bu aşamadan sonra onunmakalelerinin satır aralarında artık siyasî rejim, yönetim tarzı, millet meclisi gibi hususlara göndermeler yer almayabaşladı. Onun, Tasvîr-i Efkâr ’da yazdığı Girit isyanına dair yazılar, yerli ve yabancı basında geniş yankı uyandırdı. Buyazılardan biri olan “Şark Meselesi” adlı makalesinde ele aldığı şiddet ve vatan sevgisi içerikli düşünceleri yüzündenhükümeti zor duruma soktuğu için gazeteden uzaklaştırıldı. Bu sırada Mustafa Fazıl Paşa’nın Padişah Abdülaziz’ehitaben yazdığı Fransızca mektubu, Yeni Osmanlılar tarafından Türkçeye çevrilerek önce Muhbir ’de, sonra da Tasvîr-iEfkâr ’da yayımlandı. Bunun üzerine Muhbir gazetesinin yayını durduruldu. Yazarı Ali Suavî tutuklanarak Kastamonu’yasürgün edildi. Namık Kemal ise rütbesi yükseltilerek Erzurum Vali Muavinliğine, Ziya Paşa da benzer sebeplerle Kıbrısmutasarrıflığına tayin edildi. Ancak Namık Kemal, görev yerine gitmedi. Bu sırada Courrier d’Orient gazetesi sahibiJean Pietri, Namık Kemal ve Ziya Paşa’yı gazeteye davet etti. Mustafa Fazıl Paşa’nın Fransa’dan gönderdiği Fransızcamektubunu Namık Kemal ve Ziya Paşa’ya okuyarak, Paşa’nın ‘vatanın saadeti ve kurtuluşuna hizmet etmek üzere’"
9
+ 7,7,"Namık Kemal ve arkadaşlarını Paris’e davet ettiğini söyledi. Bu davete olumlu cevap veren Namık Kemal, Ziya Paşa veAli Suavî birlikte gizlice kaçıp 30 Mayıs 1867’de Paris’e ulaştı. Böylece mevcut hükümetle siyasî bir mücadelenin içinegirmiş oldular. Mevcut yönetime karşı siyasî mücadele sürerken Abdülaziz’in Fransa’yı ziyareti bahane edilerek Fransızhükümeti tarafından Namık Kemal ve arkadaşlarının Paris’ten çıkmaları ve Londra’ya gitmeleri sağlandı. Bu sıradaPadişahın af ve teveccühünü kazanan Mısırlı Mustafa Fazıl Paşa’nın İstanbul’a dönüş hazırlığı içinde olması onları üzdü,geleceğe dönük ümitlerini kırdı. Namık Kemal ve Ziya Paşa gittikleri Londra’da finansını Mustafa Fazıl Paşa’nınkarşıladığı Hürriyet gazetesini 29 Haziran 1868 tarihinde Yeni Osmanlılar Cemiyeti adına çıkardı. Namık Kemal,Hürriyet gazetesine yazdığı yazılarında, meşrutiyet idaresinin kurulması, idarî ve sosyal konulardaki bozukluklarıngiderilmesi, ferdin ve halkın siyasî hürriyetini elde etmesi, vatandaşın haklarının korunması, idarenin parlamentotarafından denetlenmesi gibi konuları işledi. 24 Kasım 1870’te resmî makamların “yazı yazmaması” gibi bazı şartlarınıiçeren davet mektubunu alınca İstanbul’a döndü. 1871’de Âli Paşa’nın ölümü sonrasında Namık Kemal yeniden yayınhayatına atıldı. Bu sırada Padişah olan Abdülaziz’in sert ve otoriter baskısı Namık Kemal ve arkadaşlarını Veliaht MuratEfendi’ye yakınlaştırdı. 1872’de Namık Kemal, Ebüzziya Tevfik, Avrupa’dan afla dönen Nuri (Menâpirzâde), Reşat(Kayazâde), üvey dayısı Mâhir ile birlikte bir gazete çıkartmaya teşebbüs etti. Ancak mevcut yönetimden gerekli izni"
10
+ 8,8,"| 3alamadı. Bunun üzerine arkadaşları ile birlikte bir mizah ve haber gazetesi olan İbret gazetesini kiraladı. NamıkKemal’in başyazarlığını üstlendiği İbret gazetesi, 13 Haziran 1872 tarihinde, nasıl bir yol takip edeceklerini belirten birbeyanname ile yayın hayatına başladı. Namık Kemal’in yönetimindeki İbret , günlük olaylardan bahsetmekle beraberbir fikir gazetesi hüviyetinde idi. Onun asıl siyasî mücadelesi bu gazetede başladı. Artık o, tam bir hükümet muhalifi,politikacı, sivri dilli bir gazeteci oldu. Ancak İbret, 19. sayıda Mahmud Nedim Paşa yönetiminin ağır bir dille eleştirildiği“Garaz Marazdır” başlıklı makale sebebiyle dört ay süreyle kapatıldı. Namık Kemal’e dokunmayan Sadrazam MahmutNedim Paşa, gazetenin yazarlarından Nuri, Ebüzziya Tevfik ve Reşad Beyleri taşrada bir memuriyete tayin ettirerekİstanbul’dan uzaklaştırmak istedi. Ancak İbret ’in önemli yazar kadrosu daha İstanbul’dan ayrılmadan Mahmut NedimPaşa azledildi ve yerine Midhat Paşa getirildi. Göreve yeni başlayan Midhat Paşa, Namık Kemal’i İstanbul’danuzaklaştırmak için Gelibolu mutasarrıflığına tayin etti. Namık Kemal, Gelibolu’da 26 Eylül 1872’de başladığı görevindeüç aya yakın bir zaman kalabildi. Bu zaman zarfında Gelibolu’daki memur ve eşrafın yolsuzlukları, okulların durumu vemaarif meselesinin üzerine gitti. Menfaati engellenenlerin Bâbıali’ye şikâyetleri üzerine 11 Aralık 1872’de görevindenazledildi. Bu kısa süre zarfında hem idarî yönden başarılı hem de verimli bir yazı hayatı geçirdi. Namık KemalGelibolu’da sürgün iken Midhat Paşa, İbret ’in yeniden yayımlanmasına izin verdi. Bu fırsatı da değerlendiren NamıkKemal, Gelibolu’dan B. M. (başmuharrir) rumuzu ile İbret ’te, (N. K.) imzasıyla da Ebüzziya’nın çıkardığı Hadîka ’dayazmayı sürdürdü. 1872 Aralık ayının sonunda Gelibolu’dan İstanbul’a dönen Namık Kemal tekrar İbret’in başına geçtive yeniden imzalı ve imzasız yazılar yazmaya başladı. Sadrazam Mütercim Rüşdü Paşa’nın yönetimi sırasındamatbuata baskı arttı. Kitap yayınlarına sansür getirildi. Bu durumu şiddetle eleştiren Namık Kemal’in yönetimindekiİbret , 110. sayısında bir ay süreyle kapatıldı. İbret ’in kapalı kaldığı bu süre zarfında ilk tiyatro eseri olan dört perdelikVatan Yahut Silistre ’yi tamamladı. Hayatında bir dönüm noktası olacak Vatan Yahut Silistre adlı oyunu, 1 Nisan 1873tarihinde Güllü Agop’un Gedik Paşa’daki Tiyatrosu’nda oynandı. Tiyatroyu dolduran seyircinin heyecanla seyrettiğioyunun coşkusu sokağa taştı. Halk, Namık Kemal’i tebrik etmek için gece ellerinde fener yollara düştü. Galatasaray’dagazetenin idaresine kadar gelen halk, Namık Kemal’e şükran ve tebriklerini sundukları bir mektup bıraktı. Bir sonrakigün İbret gazetesinde temsilin halk üzerindeki etkisini ele alan yazılar yayımlandı. Vatan Yahut Silistre oyunu umumîistek üzerine 3 Nisan 1873’te ve sonrasında tekrar, aynı heyecan ve coşkuyla izlendi. Türk tiyatro tarihine geçen bucoşkulu olayı, İbret gazetesi haber ve çeşitli yazılarla kamuoyuna yansıttı. Hükümet, sayfalarında Vatan Yahut Silistreile ilgili haber ve coşkulu yazılara yer veren İbret’ in yayınını 132. sayısında durdurdu (5 Nisan 1873). 6 Nisan 1873’temuzır neşriyat ve harekette bulundukları gerekçesiyle gazetenin yazar kadrosunda yer alan Ebüzziya Tevfik, Nuri Bey,Bereketzade İsmail Hakkı ve oyunun oynandığı gün tiyatroda bulunan Ahmet Midhat Efendi mahkemeye dahiçıkarılmaksızın tutuklandı. Sultan Abdülaziz’in fermanı ile de 9 Nisan 1873’te adı geçenler “ıslah-ı nefs” edene kadarkalebent olarak Hıdîv Kumpanyası’nın Mısır vapuruyla bir kısmı Rodos ve Akkâ’ya, Namık Kemal de Magosa’ya sürgünedildi. Bu sürgünün asıl sebebi Namık Kemal ve arkadaşlarının Veliaht Murad Efendi ile yakın temasta bulunmaları idi."
11
+ 9,9,"Namık Kemal, Magosa’da idarecilerden yakın ilgi gördü. Namık Kemal’in otuz sekiz ay süren sürgün hayatı 30 Mayıs1876 tarihinde Sultan Abdülaziz’in tahttan indirilmesi ve V. Murad’ın padişah olması ile sona erdi. Namık Kemalaffedilerek 19 Haziran 1876’da İstanbul’a döndü. Sultan V. Murad’ın “bedence” ve “akılca” devleti idare edemeyecekhâlde olması, Namık Kemal’i sükût-ı hayale uğrattı. V. Murad, Şeyhülislâmın fetvası ile 93 gün kaldığı tahttan indirildive yerine Meşrutî yönetimi hayata geçireceğini ve Kanûn-ı Esâsî’yi ilân edeceğini vaat eden Sultan II. Abdülhamid, 31Ağustos 1876’da tahta çıkarıldı. II. Abdülhamid, kısa bir süre sonra Namık Kemal’i Şûra-yı Devlet üyeliğine getirdi."
12
+ 10,10,Ardından Namık Kemal 7 Ekim 1876’da Kanûn-ı Esâsî’yi hazırlayacak heyet arasında yerini aldı. 23 Aralık 1876’daKanûn-ı Esâsî kabul edildi. Bu durum ülkede sevinçle karşılandı. Ancak bir kısım halkın ve askerlerin sokaklarda dolaşıp
13
+ 11,11,"| 4“Yaşasın Midhat Paşa” diye bağırmaları, Namık Kemal’in vatanî şiirlerini, bilhassa şarkı ve türkü formunda yazılmışmanzumelerini okumaları, Padişahı çok tedirgin etti. Kısa bir süre sonra II. Abdülhamid, Kanûn-ı Esâsî’nin hayatageçirilmesinde önemli rolü olanları İstanbul’dan uzaklaştırmaya başladı. Önce Süleyman Paşa’yı Hersekkumandanlığına, Ziya Paşa’yı Suriye valiliğine tayin etti. Sonra da İstanbul’da kalmak için direnen Namık Kemal’i birmemuriyete gönderebilmek için Midhat Paşa’ya baskı yapmaya başladı. Bu sürgünden Midhat Paşa’nın kendisi denasibini aldı. Sadaretten uzaklaştırıldı ve sürgüne gönderildi. Namık Kemal de tutuklandı ve yargılandı. Beş ay hapisyattıktan sonra 10 Temmuz 1877’de Padişahın iradesiyle tahliye oldu ve Midilli adasında “ikâmete memur” edildi. 19Temmuz 1877’de İstanbul’dan Midilli’ye hareket etti. Oradan da Meclis-i Mebûsan’ın faaliyetlerini takip etti. Tanıdığı vegüvendiği mebuslar vasıtasıyla hükümete yönlendirmelerde bulundu. Patlak veren Doksan üç Harbi’nin yıkımları büyükıstırap duymasına sebep oldu. Bu sırada “Vâveylâ (çığlık)”, “Vatan Mersiyesi” gibi en meşhur vatanî şiirlerini yazdı. İkibuçuk yıl sonra sürgünde bulunduğu ve kendisinin “cehennemin cenneti”, “cennet varsa, mutlaka bu yerin altındadır”"
14
+ 12,12,dediği Midilli adasına II. Abdülhamid’in iradesiyle 18 Aralık 1879 tarihinde mutasarrıf olarak tayin edildi. Mutasarrıfolduktan sonra “birçok bakımdan yönetimi zorluklarla dolu” olan Midilli’de devlet için önemli ve başarılı görevler yaptı.
15
+ 13,13,"Burada yirmiye yakın ilk mektep yaptırdı. Adada Türkün menfaatini korumak için büyük çaba gösterdi. Kendisine karşıyapılan şikâyet ve iftiralara karşı direndi. Adada ülkesi adına verdiği mücadelede II. Abdülhamid’in gizli veya açıkdesteğini gördü. Hatta Yıldız Sarayı ile doğrudan haberleşebilmesi için sarayın telgraf şifresi kendisine verildi. Midilli’degeçirdiği beş yıl, Magosa kadar verimli oldu. Burada Celâleddin Harzemşah , Cezmi , edebiyata dair görüşlerinin yeraldığı Mukaddime-i Celâl ve 1883’te Fransız fikir adamı Ernest Renan’ın İslâmiyete hücum eden bazı görüşlerine karşıkaleme aldığı Renan Müdafaanâmesi adlı eserlerini tamamladı. Severek görev yaptığı Midilli’den Hristiyan eşrafınşikâyet ve iftiraları yüzünden ayrılmak zorunda kaldı. 15 Ekim 1884’te “İrâde-i Seniyye” ile Rodos mutasarrıflığınagönderildi. On iki cilt olarak tasarladığı Osmanlı Tarihi ’ni burada yazmaya başladı. Rodos’ta da diğer adalarda olduğugibi Türklerin kültür seviyelerini yükseltmek, Türk nüfusunu artırmak ve millî kültürü korumak için çaba harcadı, birortaokul açtırdı, üç camii yaptırdı. Bu çabalarının karşılığı olarak Kasım 1886’da II. Abdülhamid tarafından “İmtiyazMadalyası” ile ödüllendirildi. Namık Kemal, 1887 yılı Aralık ayı başında, Rodos’tan Sakız’a tayin edildi. Burada sağlığıiyice bozuldu ve tutulduğu zatürreden kurtulamayarak 28 Rebîülevvel 1306 (2 Aralık 1888) Pazar günü hayatagözlerini yumdu. Cenazesi önce Sakız’da bir caminin hazîresine, vasiyeti üzerine yakın arkadaşı Ebüzziya’nın girişimive II. Abdülhamid’in desteği ile cenazesi üç gün sonra Gelibolu’ya nakledildi ve Rumeli fatihi olarak bilinen SüleymanPaşa’nın Bolayır’daki türbesi hazîresine defnedildi."
16
+ 14,14,"İlk gençlik devresinde yazdığı divan tarzı şiirleriyle edebiyat dünyasına giren Namık Kemal, asıl şöhretini vatan vehürriyet kavramını şiirleriyle işlemeye başladığı zaman kazanır. Onun bütünüyle olmasa bile şiirinin eski tarzdanuzaklaşması ve yerini sosyal konulara bırakmaya başlaması, Avrupaî fikirlere sahip bir Türk olan Şinasî’yi tanıdıktansonraya rastlar. Onun bu yöndeki gelişme ve değişmesine sebep olan şeyler, giriştiği hürriyet mücadelesi, hapis,sürgün, gurbet gibi hususların yanı sıra ülkenin siyasî ve fikrî çehresini değiştiren Bosna-Hersek isyanı, Doksanüç Harbi(1877-1878 Türk-Rus Savaşı) gibi olaylardır. O, içerik olarak gazel, kaside, murabba gibi nazım türlerinde işlediğivatan, millet, hürriyet, hak, hukuk, adalet, ahlâk, fazilet gibi kavramlar vasıtasıyla milletin gönlünde heyecanlı fırtınalaresmesini sağlar. Ona şöhret kazandıran şiirlerinden birisi 1868’de Londra’da yazdığı bilinen ve 1876’da Sırbistan veKaradağ isyanları sırasında yayımlanan “Hürriyet Kasidesi”dir. O, Batılı nazım şekillerini de Abdülhak Hamid’in “Sahrâ”"
17
+ 15,15,"şiirinin yayınlanmasından sonra dener. Hem nazım şeklinde hem de içerikte yaptığı değişiklikleri “Vâveylâ”, “VatanMersiyesi”, “Bir Muhâcir Kızın İstimdâdı”, “Hilâl-i Osmanî” gibi manzumelerinde uygular. Bu tarz yazdığı şiirlerindegerek dil, gerekse üslûp bakımından yenilikler dikkati çeker. Namık Kemal, şiirin yanı sıra fıkra, haber, makale, tarih"
18
+ 16,16,"| 5denemeleri, hal tercümeleri, tiyatro, roman ve mektup gibi edebî türlerde yazılar da yazar. Güçlü ifade tarzına sahipolan Namık Kemal, bu tür yazılarında şaşılacak derecede realisttir."
19
+ 17,17,"Namık Kemal’in en çok eser verdiği türlerden biri tiyatrodur. Tiyatroyu “en faydalı bir eğlence” aracı sayar. Yazdığı“Mukaddime-i Celâl ”de bizde ilk defa tiyatronun nazariyatını yapar. O, tiyatroyu, toplumu değiştirici etkisinden dolayıedebî türlerin en üstünde görür. Ayrıca Batıdaki “büyük siyasî inkılâplarda ve medenî ilerlemelerde tiyatronun tesirininolduğunu” ileri sürer. Namık Kemal, piyeslerinin çoğunda bir davaya inanmış insan tipini canlandırmaya çalışır."
20
+ 18,18,"Piyeslerinin kahramanları, şahsî saadetleri için değil, sosyal meseleler ve vatanî gaye uğruna kendilerini fedaedenlerden oluşur. Namık Kemal’in kendi ideal insan tiplerini canlandırdığı ve hayatta iken oynanan tek piyesi VatanYahut Silistre ’dir. Asıl adı “Râz-ı Dil” olan beş perdelik Gülnihâl adlı piyeste, zalim ve baskıcı bir yöneticiye karşı verilenmücadele ve intikam fikrini işler. Beş perdelik Âkif Bey piyesinde ise, Kırım Savaşı sırasında çok sevdiği karısınıbırakarak vatan müdafaasına koşan bir bahriye subayının karısı tarafından ihanete uğraması ve aile faciasını anlatır."
21
+ 19,19,"Üç perdelik bir trajedi olan Zavallı Çocuk ’ta bir genç kızın, istemediği zengin birisiyle evlendirilmesi ve yaşanan felaketiele alır. Beş perdelik Kara Belâ ’da da, bir Hint hükümdarının kızının şehvetten gözü dönmüş bir harem ağası tarafındantecavüze uğramasını, kızın sevdiği şehzade ile harem ağasını öldürmesini ve sonra da şehzadeyle birlikte intiharetmesini ele alır. Son tiyatro eseri Celâleddin Harzemşah ’ta ise, Namık Kemal, İslâm âlemini tehdit eden Moğolistilâsına karşı yalnız başına durmaya çalışan Celâleddin Harzemşah’ın yaşadığı macerayı işler."
22
+ 20,20,"Namık Kemal’in İntibah ve Cezmi adlı iki romanı vardır. Namık Kemal, İntibah , adlı romanını Son Pişmanlık adı ilesürgünde bulunduğu 1873-1875 yıllarında Magosa’da yazar. Ancak romanın ismi Maarif Nezâreti tarafından “İntibah-Sergüzeşt-i Ali Bey” olarak değiştirilerek 1876 yılında neşredilir. İntibah ’ta, iyi eğitimli, ancak hayatın gerçeklerikonusunda tecrübesiz olan Ali Bey’in gerçek kimliğini bilmediği ahlâken düşük bir kadına âşık olması ve âşık olduğu bukadın yüzünden yaşadığı ahlâkî çöküntü ve sonunda uğradığı felâket realist bir şekilde anlatılır. Namık Kemal’in ikinciromanı Cezmi ’dir. Bu eserini Midilli’de iken yazar. Romanda, tarihî kişiliğe sahip kahramanlardan temiz, ahlâk ve faziletsahibi bir sipahi olan Cezmi ve Kırım şehzadesi Âdil Giray’ın hikâyesi işlenir. Cezmi , tam anlamı ile romantik bir eserdir."
23
+ 21,21,"Aileden, bilhassa babasından aldığı kuvvetli bir tarih kültürüne sahip olan Namık Kemal’in tarih ve tarihî şahsiyetlerleilgili makale ve eserleri de vardır. O, Osmanlı Devleti’nin Sultan Osman’dan Kanunî Sultan Süleyman zamanına kadargelen padişahların şahsiyetleri ve yaptıkları işleri ana hatlarıyla anlattığı eseri Devr-i İstilâ ’yı yazar. Bu eser, 1866’daTasvîr-i Efkâr ’da tefrika edilir. 1867’de Evrâk-ı Perişan ’da yayımlanır. Evrâk-ı Perişan’da büyük İslâm kahramanıSelahattin’i Eyyübî’nin, hayatını anlattığı Fatih’in, hayranlık duyduğu Yavuz Sultan Selim’in, Emîr Nevruz’un destanî hâltercümelerine yer verir. O, ayrıca, Silistre Muhâsarası ve roman tadında Tiryaki Hasan Paşa’yı anlattığı Kanije adlıeserleri meydana getirir. Bu eserlerdeki kahramanlar vatan kuran, vatanın bütünlüğünü, İslâm birliğini sağlayan, haçlıve Moğol saldırılarını durduranlardır."
24
+ 22,22,"Namık Kemal, Türk edebiyatında önemli izler bırakan modern manadaki ilk eleştirmenimizdir. O, Bahâr-ı Dâniş, NevruzBey ve İntibah mukaddimeleri, Tahrîb-i Harâbât, Tâkîb, İrfan Paşa’ya Mektup, Mes Prisons Muâhezenâmesi,Mukaddime-i Celâl, Ta’lîm-i Edebiyat Üzerine Bir Risâle, Lisân-ı Osmanî’nin Edebiyatı Hakkında Bazı MülâhazâtıŞâmildir gibi eleştiri, mektup ve makalelerinde dil ve edebiyatımız hakkında değerlendirmelerde, önerilerde, çözümarayışlarında bulunur."
25
+ 23,23,"Namık Kemal, Avrupa’dan (Paris, Londra) döndükten sonra Magosa, Midilli, Rodos ve Sakız adalarında on dört yılı bulansürgün ve gurbet hayatı yaşar. Sürgün yıllarında mektup ve mektuplaşma, adeta hayatının bir parçası, teselli kaynağı"
26
+ 24,24,"| 6olur. Hayatından ve eserlerinden izler taşıyan resmî, ilmî, siyasî, tenkidî, edebî, hususî, samimî, âşıkâne, dostâne,vatanperverâne vs. on bin civarında mektup yazdığı tahmin edilen Namık Kemal’in, mektuplarını, aile fertlerine, yakındost ve akrabalarına, edebiyat çevresindeki bazı ünlü edebiyat ve düşünce adamlarına yazdığı bilinmektedir. Bir kısmıyayımlanan mektuplarında, son derece sade ve anlaşılır bir dil kullanır."
27
+ 25,25,"Millî ve İslâmî değerleri koruyarak Batılılaşma fikrini benimseyen Namık Kemal, bilhassa gazetecilik yaptığı 1863-1873yılları arasında Türk toplumunun ihtiyaç duyduğu sosyal, siyasî, ekonomik, hukukî, kültür, eğitim vs. gibi çeşitli temelkonular ile de ilgilenir ve bu hususlar üzerine yazdığı makalelerde ilgilileri ve kamuoyunu bilgilendirmeye çalışır. Onunbu çerçevedeki düşüncelerinin ana hatları, “memlekette meşrutiyet idaresinin kurulması, sosyal ve ferdî hürriyet,bilhassa fikrî hürriyet, kurumların ıslahı, Türk toplumunun Avrupa medeniyetine ayak uydurması” şeklinde çizilebilir."
28
+ 26,26,"Hürriyet ve demokrasi mücadelesi uğruna ömrünün önemli bir kısmını gurbet ve sürgünlerde geçiren Namık Kemal,fikrî bakımdan hem yaşadığı dönemde hem de ölümünden sonra edebiyatta, sosyal ve siyasî alanda fikirlerini cesurcaaktardığı yazılarıyla toplumu uyandırmaya yönelik eserleriyle, etkisini sürdüren nadir bürokrat, şair veyazarlarımızdandır. O, özellikle vatanî şiirleri ve fikrî yazılarındaki samimî ve korkusuz hitabet üslûbu ile Türk milletininvatan, hürriyet ve istiklâl mücadelesinde öncülük eden nice şair, yazar, devlet adamına rehberlik yapar."
29
+ 27,27,"Namık Kemal’in tesiri altında kalanlardan birisi de Türkiye Cumhuriyeti Devleti’nin kurucusu Gazi Mustafa KemalAtatürk’tür. Namık Kemal vefat ettiğinde Mustafa Kemal henüz yedi yaşındadır. Mustafa Kemal, Manastır İdâdîsi(lisesi)’nde öğrenci iken Namık Kemal’i tanıması yakın arkadaşı Ömer Naci Bey sayesinde olur. O sıralarda edebiyatameraklı, heyecanlı şiirler yazan ve söyleyen Ömer Naci, yazıları ve üslûbu noktasında Namık Kemal’e hayran birisidir."
30
+ 28,28,"Mustafa Kemal, bir gün ondan okuması için kitaplar ister. O da kendisine ders kitapları verir. Mustafa Kemal, ondanders kitapları istemediğini söyler. O da kendisine çeşitli şiirler ve tiyatro eserleri getirir, verir. Mustafa Kemal bunlarıkarıştırırken sayfaları arasına serpiştirilmiş el yazısı ile Namık Kemal’in “Hürriyet Kasidesi”ndeki ve “VatanMersiyesi”ndeki heyecan uyandıran şu mısralar dikkatini çeker: “Felek her türlü esbâb-ı cefasın toplasın gelsin/Dönersem kahbeyim millet yolunda bir azimetten”; “Merkez-i hâke atsalar da bizi/ Kürre-i arzı patlatır çıkarız” ve“Vatanın bağrına düşman dayadı hançerini/ Yoğ-imiş kurtaracak bahtı kara maderini”. O devirde Namık Kemal’invatanseverlik telkin eden eserleri yasaklandığı için bulmak, şiir ve yazılarındaki heyecanlı atmosferi yaşamakisteyenler aydınlar vardır. İşte Mustafa Kemal de devrin ve okulun sıkı şartları altında Namık Kemal’in eserlerindenbulduklarını ekseriyetle koğuşta, herkes yattıktan sonra kötü ışık şartları altında gizli gizli okuyarak tanımaya başlar. O,ülkenin problemlerine çözüm getirmeye çalıştığı, vatanı, hürriyeti ve insan haklarını savunduğu için Namık Kemal’ehayran olur. Bu hayranlık onda vatansever, hürriyetperver olmasının yolunu açar. Öğrencilik yılları ve sonrasında onunözellikle vatan, millet, hürriyet, medeniyet, aile, tarih, hukuk, iktisat, eğitim konularında yazdığı yazılarından veheyecan uyandıran yüksek ideallerinden, fikirlerinden etkilenir. II. Meşrutiyet hareketini gerçekleştirenler NâmıkKemâl’in Vatan Yahut Silistre piyesini yeniden sahneye koyarak seyirciyle buluştururlar. “Vatan ve Hürriyet Şairi”"
31
+ 29,29,"yazan kartpostallarını ve afişlerini yaparak geniş halk kitlelerine onu tekrar hatırlatırlar. Mustafa Kemal, arkadaşı AliFuat Cebesoy’la birlikte Manastır’da iken piyesi büyük bir heyecan ve coşkuyla seyrederler. Oyunun son sahnesinde birtalebenin okuduğu “Yâre nişandır tenine erlerin!/ Mevt ise son rütbesidir askerin!/ Altı da bir üstü de birdir yerin,/Arşyiğitler vatan imdadına ” mısralarını gözleri dolarak dinlerler. Vatan ve millet sevgisi ile donanmış Türk aydınları, zor vesıkıntılı yıllarda, Namık Kemal’in “ahlâk ve vatan dersi veren ateşli mısralarını bir âyet gibi tekrarlarlar.” 1915’teÇanakkale Savaşları sırasında cepheye giderken onun ve Süleyman Paşa’nın mezarını ziyaret eden genç milliyetçi Türksubayları mezar taşına el yazısı ile yazılar yazarlar. Bu yazılardan birinde yürek sızlatan şu cümle yer alır: “Namık"
32
+ 30,30,"| 7Kemâl, senin vatanını kurtarmak için ölmeğe gidiyorum.” Mustafa Kemal’in I. Dünya Savaşı sırasında Doğu cephesindegörevli iken 10 Ağustos 1916 Pazar günü hatıra defterine yazdıklarından, o çetin savaş yılları içinde, Namık Kemal’infikir hürriyeti ve meşrutî yönetimle ilgili görüşlerinin yer aldığı “Makalât-ı Siyasiyye ve Edebiyye” adlı eseriniokuduğunu, ardından da yine Namık Kemal’in Tarih-i Osmanî’sini okumaya başladığını öğrenmekteyiz. Ayrıca onunözel sohbetlerinde, sıkıldığı zamanlarda ve yaptığı konuşmalarda Namık Kemal’den mısralar, beyitler söylediğibilinmektedir. Millî Mücadele yıllarında işgal altındaki ülkemizin bağrında hançer dayalıdır. Mustafa Kemal Paşa, SivasKongresi’nden sonra 18 Aralık 1919’da Heyet-i Temsiliye Merkezini Ankara’ya taşımak üzere arkadaşlarıyla birlikteyola çıkar. Şarkışla, Kayseri ve Mucur’dan geçerek 24 Aralık 1919 tarihinde Kırşehir’e gelir. Halk, onu coşku ve sevgiylekarşılar. Geceleyin şerefine fener alayı tertip edilir. Kırşehir “Gençler Derneği”nde halka hitaben bir konuşma yapar."
33
+ 31,31,"Konuşmasında “Kuva-yı Milliyenin âmil, irade-i millîyenin hâkim olması” gerektiğini söyler. Konuşmasının devamındaNâmık Kemâl’in Vatan Mersiyesi ’nde yer alan: “ Vatanın bağrına düşman dayadı hançerini/ Yoğ-imiş kurtaracak bahtıkara mâderini” beytini değiştirerek şöyle okur: “ Vatanın bağrına düşman dayasın hançerini/ Bulunur kurtaracak bahtıkara maderini”. Mustafa Kemal Paşa, Namık Kemal’in aynı mısralarını I. İnönü Savaşı ile ilgili 13 Ocak 1921 tarihliMeclis oturumundaki konuşmasında aynı heyecanla okur. Büyük Millet Meclisi’nde başta Mustafa Kemal Paşa olmaküzere onun fikirlerinin tesiri altında kalan bazı milletvekilleri de Nâmık Kemâl’den parçalar okurlar. II. İnönü Zaferi’ndensonra, Namık Kemal’in oğlu Ali Ekrem, Mustafa Kemal Paşa’ya bir tebrik telgrafı çeker. Mustafa Kemal Paşa, 10 Nisan1921 tarihinde özel teşekkürü ile birlikte bu telgrafa verdiği cevapta: “ Yaralı vatanın kurtuluşu ve bağımsızlığı içinölmek yolunda, bugünkü nesle fedakârlık göstermeyi öğreten büyük Namık Kemal ”dir diyerek şaire duyduğu büyükhayranlığı ve saygısını açıkça dile getirir. İdeallerini gerçekleştirebilmek için ömrünün büyük bir kısmını mücadeleiçinde geçiren Namık Kemal’in, vatanın ve milletin istiklâli, birliği ve yükselmesi için gösterdiği çabada Gazi MustafaKemal Paşa’yı “vatan, millet, hürriyet, bayrak, dil, din, eşitlik, medeniyet, hak, hukuk” vs. gibi kavramlar ve heyecanyüklü milliyetçi fikirleriyle etkiler. Bu kavramlardan hareketle ona “hürriyet ve bağımsızlık benim karakterimdir”"
34
+ 32,32,"sözünü söyleten düşüncenin asıl kaynaklarından biri de Namık Kemal’dir. Mustafa Kemal Atatürk’ün özelkütüphanesinde yer alan Namık Kemal’in kitapları, bu etkinin kaynağı ve ona gösterdiği ilginin delilidir. TürkiyeCumhuriyeti Devleti’nin kurucusu ulu önder Mustafa Kemal Atatürk, Namık Kemal’in ortaya koyduğu ilke ve kavramlarıömrü boyunca savunur. Ancak o, etkisinde kaldığını ifade ettiğimiz Namık Kemal’in düşüncelerini olduğu gibi alan vesavunan biri olarak da düşünülmemelidir."
35
+ 33,33,"Türk şiiri ve edebiyatına vatan, millet, hürriyet gibi kavramları kazandıran ve bu kavramlar uğruna seve seve canverilebileceğini eserlerinde vurgulayan ve millette heyecan dalgalarının oluşmasını sağlayan Namık Kemal, yaşadığıdevirde olduğu gibi günümüzdeki ve sonrasındaki nesilleri vatan, millet, hürriyet ve istiklâl mücadelesi için yolaçıkanları ve çıkacak olanları bu parlattığı kıvılcımlarla sonsuza kadar etkilemeye devam edecektir."
36
+ 34,34,"Erol ÜLGENKAYNAKÇAAKÜN, Ömer Faruk, “Kıbrıs Basamağında Namık Kemal”, Namık Kemal Sempozyumu Bildirileri, Gazimağusa27-28 Nisan 1998 , Gazimağusa-KKTC 1998."
37
+ 35,35,"AKÜN, Ömer Faruk, “Namık Kemal (1840-1888)”, TDV İslâm Ansiklopedisi , 32. Cilt, İstanbul 2006, s.361-378."
38
+ 36,36,"AKÜN, Ömer Faruk, “Nâmık Kemal’in Kitap Halindeki Eserlerinin İlk Neşirleri”, Türkiyat Mecmuası , C XVII, 1973-1975,"
39
+ 37,37,| 8İstanbul 1976.
40
+ 38,38,"AKÜN, Ömer Faruk, “Namık Kemal”, İslâm Ansiklopedisi , 9. Cilt, Millî Eğitim Basımevi, İstanbul 1988."
41
+ 39,39,"ALDAN, Mehmet, Mutasarrıf Namık Kemal , XI. Türk Tarih Kongresi’nden ayrı basım, Ankara 1994."
42
+ 40,40,"Atatürk’ün Söylev ve Demeçleri I (1919-1918) , 2. Baskı, Türk Tarih Kurumu Basımevi, Ankara 1961."
43
+ 41,41,"BERKES, Niyazi, Türkiye’de Çağdaşlaşma , Doğu-Batı Yayınları, İstanbul 1978."
44
+ 42,42,"BİLGEGİL, M. Kaya, Harâbât Karşısında Nâmık Kemâl , İstanbul 1972."
45
+ 43,43,"BOLAYIR, Ali Ekrem, Namık Kemal , Millî Eğitim Bakanlığı Yayınları, İstanbul 1992."
46
+ 44,44,"CEBESOY, Ali Fuat, Sınıf Arkadaşım Atatürk , 2. Baskı, İnkılâp Kitabevi, İstanbul 1981."
47
+ 45,45,"ÇAĞAN, Kenan, “Namık Kemal’de Devletin Niteliği ve Temel Dayanakları”, Akademik İncelemeler Dergisi , C 7, S 1,2012, s.255-280."
48
+ 46,46,"DOĞRU, Sami, “Bir Mektub…”, A. Hilmi Yücebaş, Namık Kemâl ve Vatan Sevgisi , Tekirdağ İl Basımevi, Tekirdağ1937."
49
+ 47,47,"DUMAN, Hasan, “Atatürk ve Nâmık Kemal”, Millî Kültür , S 64, Nisan 1989, s.27-33."
50
+ 48,48,"Ebuzziya Tevfik, Yeni Osmanlılar , Günümüz Türkçesine Uygulayan Şemsettin Kutlu, Pegasus Yayınları, İstanbul 2006."
51
+ 49,49,"EMİL, Birol, “Namık Kemal’in Eserinde ve Aksiyonunda Üç Temel Kavram: Hürriyet-Medeniyet-İrade”, Ölümünün 100."
52
+ 50,50,"Yılında Namık Kemal , Marmara Üniversitesi Fen-Edebiyat Fakültesi, İstanbul 1988."
53
+ 51,51,"ENGİNÜN, İnci, Yeni Türk Edebiyatı Tanzimat’tan Cumhuriyete (1839-1923) , Dergâh Yayınları, İstanbul 2006."
54
+ 52,52,"ERCİLASUN, Bilge, “Eleştiri (1860-1923)”, Türk Edebiyatı Tarihi 3 , Ed. Talât Sait Halman vd.leri, Türk KültürünüAraştırma Enstitüsü, İstanbul 2006."
55
+ 53,53,"EROĞLU, Haldun, “Mustafa Kemal Atatürk’ün Düşün Dünyasının Oluşumundaki Etkenlerle İlgili Bazı Görüşler”, AtatürkYolu , C 7, S 27, Mayıs-Kasım 2001 s.289."
56
+ 54,54,"FEYZİOĞLU, Turhan, “Türk Millî Mücadelesinin ve Atatürkçülüğün Temel İlkelerinden Biri Olarak MilletEgemenliği”, Atatürkçü Düşünce , Atatürk Araştırma Merkezi Yayınları, Ankara 1992."
57
+ 55,55,"GÖÇGÜN, Önder, “Atatürk ve Edebiyat”, Edebiyat Dünyası ve Atatürk , Atatürk Kültür Merkezi Yayınları, Ankara1995."
58
+ 56,56,"GÖÇGÜN, Önder, “Atatürk ve Namık Kemal”, Doğumunun Yüzellinci Yılında Namık Kemal , Marmara ÜniversitesiFen-Edebiyat Fakültesi, Ankara 1993."
59
+ 57,57,"GÖÇGÜN, Önder, “Nâmık Kemâl’de Tarih Düşüncesi ve Sevgisi”, Yeni Türk Edebiyatı Araştırmaları I , SelçukÜniversitesi Yayınları, Konya 1991."
60
+ 58,58,"GÖZCÜ, Alev, “Atatürk’ün Düşünce Dünyasında Namık Kemal’in Etkisi”, Doğumunun 170. Yılında UluslararasıNamık Kemal Sempozyumu , 20-22 Aralık 2010 Tekirdağ , Ed. Orhan Kemâl Tavukçu, Ali Tilbe, Cilt I, Tekirdağ2010."
61
+ 59,59,"| 9İLTER, Erdal, “Atatürk’ün Etkilendiği Fikir Akımları ve Onun Öğrencilik Yılları”, Prof. Dr. Abdurrahman Çaycı’yaArmağan , Hacettepe Üniversitesi Atatürk İlkeleri ve İnkılâp Tarihi Enstitüsü, Ankara 1995."
62
+ 60,60,"KAPLAN, Mehmet, Namık Kemal Hayatı ve Eserleri , İstanbul Üniversitesi Edebiyat Fakültesi Yayınları, İstanbul 1948."
63
+ 61,61,"KAPTANOĞLU, Muazzez, “Münevverlerin Gözü ile Namık Kemal”, İnsan , C 2, S 8, 1939, s.622."
64
+ 62,62,"KARAKARTAL, Oğuz, ARSLAN, İbrahim, “Nâmık Kemâl Üzerine Bir Kolaj”, Nâmık Kemâl , Ed. Turan Karataş, OrhanKemâl Tavukçu, T.C. Kültür ve Turizm Bakanlığı, Ankara 2011, s.106-107, 109."
65
+ 63,63,"KAVCAR, Cavit, “Namık Kemal’in Üslûp Anlayışı”, Doğumunun Yüzellinci Yılında Namık Kemal , MarmaraÜniversitesi Fen-Edebiyat Fakültesi, Ankara 1993."
66
+ 64,64,"KORAP, Ali Rıza, “Namık Kemal”, Bilgi Yurdu , S 5, Birinci kânun (Kasım 1938), s.534."
67
+ 65,65,"KUNTAY, Midhat Cemal, Namık Kemal Devrinin İnsanları ve Olayları Arasında , Cilt 1, İş Bankası Yayınları,İstanbul 2010."
68
+ 66,66,"Namık Kemal, “Garaz Marazdır”, İbret , Sayı 19, 3 Cumâdelûlâ (Cemâziyelevvel)1289-27 Haziran 1288."
69
+ 67,67,"Namık Kemal, “Hürriyet Kasidesi”, Vakit , Sayı 236, 10 Cumâdelûlâ (Cemâziyelevvel) 1293-21 Mayıs (Rumî) 1292-2Haziran 1876."
70
+ 68,68,"Namık Kemal, “Lisân-ı Osmanî’nin Edebiyatı Hakkında Bazı Mülâhazâtı Şâmildir “, Tasvîr-i Efkâr , Sayı 416, 16Rebiülâhir 1283; Sayı 417, 19 Rebülâhir 1283."
71
+ 69,69,"Namık Kemal, “Şark Mes’elesine Dair Bir Lâyihadır”, Tasvîr-i Efkâr , Sayı 465, 4 Zilkade 1283-28 Şubat 1283."
72
+ 70,70,"OKAY, M. Orhan, “İntibah Romanı Etrafında”, Ölümünün 100. Yılında Namık Kemal , Marmara Üniversitesi Fen-Edebiyat Fakültesi, İstanbul 1988."
73
+ 71,71,"ÖZGÜL, M. Kayahan, “Osmanlı’nın Son Encümen-i Şuarâ’sı”, Türk Edebiyatı Tarihi 3 , Ed. Talât Sait Halman vd.leri,Türk Kültürünü Araştırma Enstitüsü, İstanbul 2006."
74
+ 72,72,"ÖZÖN, Mustafa Nihat, Namık Kemal ve İbret Gazetesi , Yapı Kredi Yayınları, İstanbul 1997."
75
+ 73,73,"Sadettin Nüzhet, Namık Kemal Hayatı ve Şiirleri , Yeni Şark Kitaphanesi, İstanbul 1933."
76
+ 74,74,"SAV, Ergun, Atatürk ve İki Büyük Türk Düşünürü, Namık Kemal-Ziya Gökalp , Bilgi Yayınevi, İstanbul 2001."
77
+ 75,75,"SÖNMEZ, Cemil, Atatürk’te Edebiyat Sevgisi , Kültür Bakanlığı Yayınları, Ankara 1998."
78
+ 76,76,"Şemsettin Sâmi, Kâmûsu’l-Âlâm , Cilt 5, Tıpkı Basım, Ankara 1996."
79
+ 77,77,"TANPINAR, Ahmet Hamdi, “Namık Kemal’in Hayatı ve Eserleri”, Edebiyat Üzerine Makaleler , Haz. Zeynep Kerman,2. Baskı, Dergâh Yayınevi, İstanbul 1977."
80
+ 78,78,"TANPINAR, Ahmet Hamdi, 19. Asır Türk Edebiyatı Tarihi , 4. Baskı, Çağlayan Yayınevi, İstanbul 1976."
81
+ 79,79,"TANSEL, Fevziye Abdullah, “Namık Kemal’in Midilli’de Yazdığı Manzum ve Mensur Eserler”, Türkiyat Mecmuası , C XII,İstanbul 1955, s.58."
82
+ 80,80,"| 10TANSEL, Fevziye Abdullah, Namık Kemal’in Hususî Mektupları , Cilt I-IV, Türk Tarih Kurumu, Ankara 1967-1986."
83
+ 81,81,"TEVETOĞLU, Fethi, “Namık Kemal’in Türk Nesilleri Üzerindeki Tesiri”, Ölümünün 100. Yılında Namık Kemal ,Marmara Üniversitesi Fen-Edebiyat Fakültesi, İstanbul 1988."
84
+ 82,82,"TEZCAN, Mahmut, “Atatürk’ün Eğitim Anlayışına Felsefî ve Sosyolojik Bir Yaklaşım”, Atatürkçü Düşünce , yy., 1992."
85
+ 83,83,"TÖRENEK, Mehmet, “Nâmık Kemâl’in Romancılığı”, Nâmık Kemâl , Ed. Turan Karataş, Orhan Kemâl Tavukçu, T.C."
86
+ 84,84,"Kültür ve Turizm Bakanlığı, Ankara 2011."
87
+ 85,85,"TURAL, Sadık, “Tarihî Roman Geleneği veya Cezmi”, Doğumunun Yüzellinci Yılında Namık Kemal , Atatürk KültürMerkezi Yayınları, Ankara 1993."
88
+ 86,86,"TURAN, Şerafettin, Atatürk’ün Düşünce Yapısını Etkileyen Olaylar, Düşünceler , Kitaplar , 2. Baskı, Türk TarihKurumu, Ankara 1989."
89
+ 87,87,"TURAN, Şerafettin, Kendine Özgü Bir Yaşam ve Kişilik Mustafa Kemal Atatürk , Bilgi Yayınevi, Ankara 2004."
90
+ 88,88,"UÇMAN, Abdullah, “Namık Kemal Üzerine Bir Biyografi Denemesi”, Ölümünün 100. Yılında Namık Kemal , MarmaraÜniversitesi Fen-Edebiyat Fakültesi, İstanbul 1988."
91
+ 89,89,"ÜLKEN, Hilmi Ziya, Türkiye’de Çağdaş Düşünce Tarihi , 3. Baskı, Ülken Yayınları, İstanbul 1992."
92
+ 90,90,"YAZICI, Nevin, Osmanlılık Fikri ve Genç Osmanlılar Cemiyeti , Kültür Bakanlığı Yayınları, Ankara 2002."
93
+ 91,91,"YÜCEBAŞ, A. Hilmi, Namık Kemâl ve Vatan Sevgisi , Tekirdağ İl Basımevi, Tekirdağ 1937."
94
+ 92,92,14/06/2023 tarihinde https://ataturkansiklopedisi.gov.tr/bilgi/namik-kemal-1840-1888/?pdf=3932 adresindenerişilmiştir
temp/e077ededc99f2684258e363f44913e32.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c8fbdc82bf42ad750c47a02a2d561d04ad7c9ff3c4975f5b92e683ab966b884a
3
+ size 55458
temp/e077ededc99f2684258e363f44913e32.csv ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ,index,text
2
+ 0,0,"845-668-6613jobs@ nuravine.com1574 N Y -28 W est H urley , N Y 12491Job T itle: Embedded Systems EngineerLocation: New Y ork, USA (Remote)"
3
+ 1,1,"Salary: $70,000 - $80,000 per yearT ype: Full-time RemoteAbout Us:"
4
+ 2,2,"W e are Nuravine, a passionate and innovative company focused on revolutionizing indoor farming through IoTtechnology . Our mission is to make farming significantly more ef ficient, reducing the land needed for agriculture andpromoting reforestation. W e're not just about functionality; we see our systems as pieces of art that our customers willlove. W e're also looking towards the future, with ambitions to develop technology for use in outer space andterraforming."
5
+ 3,3,The Role:
6
+ 4,4,"W e're looking for a dedicated Firmware Developer to join our team. Y ou'll be working with real hardware systems,running tests, and writing firmware. This is a hands-on role where you'll have the opportunity to make a real impact onour product and, by extension, the future of farming."
7
+ 5,5,Responsibilities:
8
+ 6,6,"● Develop and implement firmware for our IoT devices● Collaborate with the team to optimize hardware systems through firmware● Conduct and assist in hardware testing through programming the firmware● Continually update and improve system functionality and ef ficiency● Use AI tools like ChatGPT to improve workflow● W rite reusable, flexible, and modular framework-style code at a high levelRequirements:"
9
+ 7,7,"● Degree in Computer Science, Electrical Engineering, or related field● Experience in firmware development● Knowledge of IoT technologies● Proficiency in C++ and experience with V isual Studio Code● Experience with ESP32 is a major plus● Strong problem-solving skills● Strong understanding of abstraction, object orientation, and structural programming● Passion for our mission to revolutionize farming and make the world a better placeWhy Join Us:"
10
+ 8,8,● Be part of a company that cares deeply about its product and its impact● W ork on innovative technology with real-world applications● Contribute to a sustainable future and the advancement of space technology● Join a passionate team that views our systems as functional pieces of art
webui.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import xxhash
3
+ from gradio.components import _Keywords
4
+
5
+ from ai import AI
6
+ from config import Config
7
+ from contents import *
8
+ from storage import Storage
9
+
10
+
11
+ def webui(cfg: Config):
12
+ """Run the web UI."""
13
+ Webui(cfg).run()
14
+
15
+
16
+ class Webui:
17
+ def __init__(self, cfg: Config):
18
+ self.cfg = cfg
19
+ self.ai = AI(cfg)
20
+
21
+ def _save_to_storage(self, contents, hash_id):
22
+ print(f"Saving to storage {hash_id}")
23
+ print(f"Contents: \n{contents}")
24
+ self.storage = Storage.create_storage(self.cfg)
25
+ if self.storage.been_indexed(hash_id):
26
+ return 0
27
+ else:
28
+ embeddings, tokens = self.ai.create_embeddings(contents)
29
+ self.storage.add_all(embeddings, hash_id)
30
+ return tokens
31
+
32
+ def _get_hash_id(self, contents):
33
+ return xxhash.xxh3_128_hexdigest('\n'.join(contents))
34
+
35
+ def run(self):
36
+ with gr.Blocks() as demo:
37
+
38
+ hash_id_state = gr.State()
39
+ init_page = gr.Column()
40
+ chat_page = gr.Column(visible=False)
41
+
42
+ with init_page:
43
+ with gr.Tab("url"):
44
+ url_error_box = gr.Textbox(label="Input Error", visible=False)
45
+ url_box = gr.Textbox(label="URL")
46
+ url_submit_btn = gr.Button("Submit url", variant="primary")
47
+
48
+ def submit(url):
49
+ url = url.strip()
50
+ if len(url) == 0:
51
+ return {url_error_box: gr.update(value="Enter URL", visible=True)}
52
+ try:
53
+ print(f"Crawling URL {url}")
54
+ content, lang = web_crawler_newspaper(url)
55
+ if len(content) == 0:
56
+ return {url_error_box: gr.update(value="Can not crawl this url", visible=True)}
57
+ hash_id = self._get_hash_id(content)
58
+ self._save_to_storage(content, hash_id)
59
+ except Exception as e:
60
+ return {url_error_box: gr.update(value=str(e), visible=True)}
61
+ return {
62
+ url_error_box: gr.update(visible=False),
63
+ url_box: gr.update(value=""),
64
+ init_page: gr.update(visible=False),
65
+ chat_page: gr.update(visible=True),
66
+ hash_id_state: hash_id
67
+ }
68
+
69
+ url_submit_btn.click(
70
+ submit,
71
+ [url_box],
72
+ [init_page, url_error_box, chat_page, url_box, hash_id_state],
73
+ )
74
+
75
+ with gr.Tab("file"):
76
+ file_error_box = gr.Textbox(label="Input Error", visible=False)
77
+ file_box = gr.File(label="File", file_types=["pdf", "txt", "docx"])
78
+ file_submit_btn = gr.Button("Submit file", variant="primary")
79
+
80
+ def submit(file):
81
+ url = file.name
82
+ if url.endswith('.pdf'):
83
+ contents, lang = extract_text_from_pdf(url)
84
+ elif url.endswith('.txt'):
85
+ contents, lang = extract_text_from_txt(url)
86
+ elif url.endswith('.docx'):
87
+ contents, lang = extract_text_from_docx(url)
88
+ else:
89
+ return {file_error_box: gr.update(value="Can not read this file", visible=True)}
90
+
91
+ if len(contents) == 0:
92
+ return {file_error_box: gr.update(value="Empty file", visible=True)}
93
+ hash_id = self._get_hash_id(contents)
94
+ self._save_to_storage(contents, hash_id)
95
+
96
+ return {
97
+ init_page: gr.update(visible=False),
98
+ chat_page: gr.update(visible=True),
99
+ file_box: gr.update(value=_Keywords.NO_VALUE),
100
+ file_error_box: gr.update(visible=False),
101
+ hash_id_state: hash_id
102
+ }
103
+
104
+ file_submit_btn.click(
105
+ submit,
106
+ [file_box],
107
+ [init_page, chat_page, file_box, file_error_box, hash_id_state],
108
+ )
109
+
110
+ with chat_page:
111
+ with gr.Row():
112
+ with gr.Column():
113
+ chatbot = gr.Chatbot()
114
+ kw_box = gr.Dataset(components=[gr.Textbox(visible=False)],
115
+ label="Query keywords",
116
+ samples=[],
117
+ visible=False,
118
+ )
119
+ msg = gr.Textbox(label="Query")
120
+ submit_box = gr.Button("Submit", variant="primary")
121
+ reset_box = gr.Button("Reset")
122
+ with gr.Column():
123
+ dataset_box = gr.Dataset(components=[gr.Textbox(visible=False)],
124
+ label="Context",
125
+ samples=[],
126
+ visible=False,
127
+ )
128
+
129
+ def respond(message, chat_history, hash_id):
130
+ kw = self.ai.get_keywords(message)
131
+ if len(kw) == 0 or hash_id is None:
132
+ return "", chat_history
133
+ _, kw_ebd = self.ai.create_embedding(kw)
134
+ ctx = self.storage.get_texts(kw_ebd, hash_id)
135
+ print(f"Context: \n{ctx}")
136
+ bot_message = self.ai.completion(message, ctx)
137
+ chat_history.append((message, bot_message))
138
+ return "", chat_history, dataset_box.update(samples=[[item] for item in ctx][:20], visible=True), \
139
+ kw_box.update(samples=[[item.strip()] for item in kw.split(',')], visible=True)
140
+
141
+ def reset():
142
+ return {
143
+ init_page: gr.update(visible=True),
144
+ chat_page: gr.update(visible=False),
145
+ chatbot: gr.update(value=[]),
146
+ msg: gr.update(value=""),
147
+ hash_id_state: None,
148
+ }
149
+
150
+ msg.submit(respond, [msg, chatbot, hash_id_state], [msg, chatbot, dataset_box, kw_box])
151
+ submit_box.click(respond, [msg, chatbot, hash_id_state], [msg, chatbot, dataset_box, kw_box])
152
+ reset_box.click(reset, None, [init_page, chat_page, chatbot, msg, dataset_box, hash_id_state])
153
+ demo.title = "Chat Web"
154
+ #demo.launch(server_port=self.cfg.webui_port, server_name=self.cfg.webui_host, show_api=False)
155
+ demo.launch(share=True)