Oussama commited on
Commit
77f7bce
·
0 Parent(s):

clean deploy — no binary files

Browse files
Files changed (15) hide show
  1. .gitignore +6 -0
  2. README.md +64 -0
  3. app.py +90 -0
  4. clients.py +16 -0
  5. enrichment.py +22 -0
  6. evaluation.py +106 -0
  7. evaluation_results.csv +70 -0
  8. ingestion.py +87 -0
  9. memory.py +36 -0
  10. models.py +13 -0
  11. pipeline.py +49 -0
  12. prompt.py +70 -0
  13. requirements.txt +269 -0
  14. retrieval.py +59 -0
  15. storage.py +99 -0
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ #ignore the environment file and the .gitignore itself
2
+ .env
3
+ .gitignore
4
+ rag_env/
5
+ **/__pycache__/
6
+ *.pdf
README.md ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Document RAG
3
+ emoji: ⚖️
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: streamlit
7
+ sdk_version: 1.56.0
8
+ python_version: 3.12
9
+ app_file: app.py
10
+ pinned: false
11
+ ---
12
+
13
+
14
+ # 📄 DocuRAG — Advanced RAG Pipeline for Document Q&A
15
+
16
+ A production-grade Retrieval-Augmented Generation (RAG) system that lets you upload any PDF and have an intelligent conversation about its contents. Built with advanced retrieval techniques, hybrid search, and conversational memory.
17
+
18
+ ---
19
+
20
+ ## 🚀 Live Demo
21
+
22
+ > Deployed on Hugging Face Spaces — [link coming soon]
23
+
24
+ ---
25
+
26
+ ## 🧠 What Makes This GOOD
27
+
28
+ Although it might seem like an overkill for a personal project, I wanted to implement advanced and sophisticated approaches to learn the most!
29
+
30
+ | Component | Technique |
31
+ |---|---|
32
+ | **Chunking** | Semantic chunking (sentence-transformers) + Recursive 512-Token |
33
+ | **Embeddings** | OpenAI `text-embedding-3-small` (dense, 1536d) |
34
+ | **Sparse Vectors** | BM25 via FastEmbed (`Qdrant/bm25`) |
35
+ | **Retrieval** | Hybrid search (dense + sparse) with Reciprocal Rank Fusion (RRF) |
36
+ | **Reranking** | Cohere Rerank v3.5 |
37
+ | **Generation** | GPT-4o-mini with structured prompt engineering |
38
+ | **Memory** | Sliding window + LLM-based summarization of older turns |
39
+ | **Vector Store** | Qdrant Cloud (free tier, persistent) |
40
+ | **UI** | Streamlit with streaming responses |
41
+
42
+ ---
43
+
44
+ ## 🧪 Evaluation
45
+
46
+ The project includes a RAGAS evaluation pipeline (`evaluation/evaluate.py`) that measures:
47
+ - **Faithfulness** — are answers grounded in the retrieved context?
48
+ - **Answer Relevancy** — does the answer address the question?
49
+ - **Context Precision** — are the retrieved chunks actually relevant?
50
+ - **Context Recall** — are all relevant chunks being retrieved?
51
+
52
+ [Based on a single Erasmus Italian PDF document that has 23 pages](https://www.uniurb.it/it/cdocs/INT/10047-INT-04122025173718-int_bando.pdf), the scores were:
53
+ - faithfulness: 0.8807
54
+ - answer_relevancy: 0.7479
55
+ - llm_context_precision_without_reference: 0.8843
56
+
57
+ Results saved to evaluation_results.csv
58
+
59
+ ---
60
+
61
+ ## 👤 Author
62
+
63
+ Built by **Oussama Hassine** as a portfolio project while transitioning into AI Engineering.
64
+ - LinkedIn: [Oussama Hassine](https://linkedin.com/in/OussemaHassine)
app.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import tempfile
4
+ from pipeline import process_document, COLLECTION_NAME
5
+ from retrieval import retrieve
6
+ from memory import update_memory, prompt_with_memory
7
+ from prompt import generate_response_stream
8
+
9
+ st.set_page_config(page_title="Document RAG", layout="wide")
10
+ st.title("Document RAG")
11
+
12
+ # ---- SESSION STATE INITIALIZATION ----
13
+ if "messages" not in st.session_state:
14
+ st.session_state.messages = []
15
+ if "summary" not in st.session_state:
16
+ st.session_state.summary = ""
17
+ if "uploaded_files" not in st.session_state:
18
+ st.session_state.uploaded_files = []
19
+
20
+ # ---- SIDEBAR: Configuration & Upload ----
21
+ with st.sidebar:
22
+ st.header("Upload Document")
23
+ uploaded_files = st.file_uploader("Upload Documents", type="pdf", accept_multiple_files=True)
24
+ method = st.selectbox("Chunking Strategy", ["semantic", "recursive"])
25
+
26
+ if uploaded_files and st.button("Build Knowledge Base"):
27
+ with st.status("Processing documents...") as status:
28
+ for uploaded_file in uploaded_files:
29
+ try:
30
+ st.write(f"Processing {uploaded_file.name}...")
31
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
32
+ tmp_file.write(uploaded_file.getbuffer())
33
+ tmp_path = tmp_file.name
34
+ try:
35
+ process_document(tmp_path, method=method)
36
+ if uploaded_file.name not in st.session_state.uploaded_files:
37
+ st.session_state.uploaded_files.append(uploaded_file.name)
38
+ finally:
39
+ os.remove(tmp_path)
40
+ except Exception as e:
41
+ st.error(f"Failed to process {uploaded_file.name}: {e}")
42
+ status.update(label="Processing complete!", state="complete", expanded=False)
43
+
44
+ if st.session_state.uploaded_files:
45
+ st.divider()
46
+ st.subheader("Knowledge Base")
47
+ for fname in st.session_state.uploaded_files:
48
+ st.markdown(f"- {fname}")
49
+
50
+ if st.button("Clear Chat History"):
51
+ st.session_state.messages = []
52
+ st.session_state.summary = ""
53
+ st.rerun()
54
+
55
+ # ---- CHAT INTERFACE ----
56
+ for message in st.session_state.messages:
57
+ with st.chat_message(message["role"]):
58
+ st.markdown(message["content"])
59
+
60
+ if st.session_state.uploaded_files:
61
+ if query := st.chat_input("Ex: What are the termination clauses?"):
62
+ with st.chat_message("user"):
63
+ st.markdown(query)
64
+
65
+ # 1. Update Memory
66
+ st.session_state.messages, st.session_state.summary = update_memory(
67
+ st.session_state.messages, st.session_state.summary
68
+ )
69
+
70
+ # 2. Retrieval with Status UI
71
+ with st.spinner("Searching document..."):
72
+ retrieved_chunks = retrieve(COLLECTION_NAME, query, top_k=5)
73
+
74
+ # 3. Prompt Construction
75
+ messages = prompt_with_memory(query, retrieved_chunks, st.session_state.summary, st.session_state.messages)
76
+
77
+ # 4. Streaming Response
78
+ with st.chat_message("assistant"):
79
+ response = st.write_stream(generate_response_stream(messages))
80
+
81
+ # 5. Display Sources neatly
82
+ with st.expander("View Evidence (Sources)"):
83
+ for i, chunk in enumerate(retrieved_chunks):
84
+ st.info(f"**Source {i+1}:**\n\n{chunk}")
85
+
86
+ # Update Session State
87
+ st.session_state.messages.append({"role": "user", "content": query})
88
+ st.session_state.messages.append({"role": "assistant", "content": response})
89
+ else:
90
+ st.info("👋 Welcome! Please upload a PDF in the sidebar to begin the analysis.")
clients.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from qdrant_client import QdrantClient
2
+ from dotenv import load_dotenv
3
+ import os
4
+ from openai import OpenAI
5
+ load_dotenv()
6
+ from fastembed import SparseTextEmbedding
7
+ import cohere
8
+
9
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
10
+ cohere_client = cohere.ClientV2(api_key=os.getenv("COHERE_API_KEY"))
11
+ qdrant_client = QdrantClient(
12
+ url=os.getenv("CLUSTER_ENDPOINT"),
13
+ api_key=os.getenv("QDRANT_API_KEY"),
14
+ timeout=20
15
+ )
16
+ sparse_model = SparseTextEmbedding(model_name="Qdrant/bm25")
enrichment.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from models import Chunk
2
+ import os
3
+ from openai import OpenAI
4
+ import time
5
+ from dotenv import load_dotenv
6
+ from clients import client
7
+
8
+ load_dotenv()
9
+ def add_summary(chunks: list[Chunk]) -> list[Chunk]:
10
+ """Add a summary to an existing chunk."""
11
+ for chunk in chunks:
12
+ response = client.chat.completions.create(
13
+ model="gpt-4o-mini",
14
+ messages=[
15
+ {"role": "system", "content": "You are a document assistant."},
16
+ {"role": "user", "content": f"Summarize this chunk: {chunk.text}"}
17
+ ]
18
+ )
19
+ summary = response.choices[0].message.content
20
+ chunk.summary = summary
21
+ time.sleep(0.5) # Sleep to respect rate limits
22
+ return chunks
evaluation.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import pandas as pd
4
+ from langchain_core.documents import Document
5
+ from langchain_openai import ChatOpenAI, OpenAIEmbeddings
6
+ from ragas import evaluate, EvaluationDataset, SingleTurnSample
7
+ from ragas.llms import LangchainLLMWrapper
8
+ from ragas.embeddings import LangchainEmbeddingsWrapper
9
+ from ragas.testset import TestsetGenerator
10
+ from ragas.metrics import Faithfulness, ResponseRelevancy, LLMContextPrecisionWithoutReference
11
+ from dotenv import load_dotenv
12
+ from ragas.llms import llm_factory
13
+ from ragas.embeddings import OpenAIEmbeddings as RagasOpenAIEmbeddings
14
+ from clients import client
15
+ from ingestion import get_chunks
16
+ from retrieval import retrieve
17
+ from prompt import get_answer_non_streaming
18
+
19
+ load_dotenv()
20
+
21
+ # ---- LLMs and Embeddings ----
22
+ generator_llm = llm_factory("gpt-4o-mini", client=client)
23
+ embedding_model = RagasOpenAIEmbeddings(model="text-embedding-3-small", client=client)
24
+
25
+ evaluator_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o-mini"))
26
+ evaluator_embeddings = LangchainEmbeddingsWrapper(OpenAIEmbeddings(model="text-embedding-3-small"))
27
+
28
+ # ---- Convert chunks to LangChain Documents ----
29
+ def get_documents(path: str, method: str = "recursive") -> list[Document]:
30
+ chunks = get_chunks(path, method=method)
31
+ return [
32
+ Document(
33
+ page_content=chunk.text,
34
+ metadata={"filename": chunk.source_filename}
35
+ )
36
+ for chunk in chunks
37
+ ]
38
+
39
+ # ---- Generate testset (with caching) ----
40
+ def generate_testset(path: str, num_samples: int = 20) -> pd.DataFrame:
41
+ cache_path = "testset_cache.csv"
42
+ if os.path.exists(cache_path):
43
+ print("Loading cached testset...")
44
+ return pd.read_csv(cache_path)
45
+
46
+ print("Generating testset (this takes a while)...")
47
+ generator = TestsetGenerator(llm=generator_llm, embedding_model=embedding_model)
48
+ docs = get_documents(path)
49
+ testset = generator.generate_with_langchain_docs(docs, testset_size=num_samples)
50
+ df = testset.to_pandas()
51
+ df.to_csv(cache_path, index=False)
52
+ print(f"Testset saved to {cache_path}")
53
+ return df
54
+
55
+ # ---- Run RAG + Evaluate ----
56
+ def evaluate_rag(df: pd.DataFrame, collection_name: str):
57
+ questions = df["user_input"].tolist()
58
+ truth = df["reference"].tolist()
59
+
60
+ generated_answers = []
61
+ retrieved_chunks_list = []
62
+
63
+ print(f"Running RAG on {len(questions)} questions...")
64
+ for i, question in enumerate(questions):
65
+ print(f" [{i+1}/{len(questions)}] {question[:60]}...")
66
+ retrieved_chunks = retrieve(collection_name, question, top_k=5)
67
+ retrieved_chunks_list.append(retrieved_chunks)
68
+ answer = get_answer_non_streaming(question, retrieved_chunks)
69
+ generated_answers.append(answer)
70
+ time.sleep(7) # avoid Cohere rate limit
71
+
72
+ # Build RAGAS EvaluationDataset
73
+ samples = [
74
+ SingleTurnSample(
75
+ user_input=q,
76
+ response=a,
77
+ retrieved_contexts=c,
78
+ reference=r
79
+ )
80
+ for q, a, c, r in zip(questions, generated_answers, retrieved_chunks_list, truth)
81
+ ]
82
+ dataset = EvaluationDataset(samples=samples)
83
+
84
+ print("Evaluating with RAGAS...")
85
+ results = evaluate(
86
+ dataset=dataset,
87
+ metrics=[
88
+ Faithfulness(),
89
+ ResponseRelevancy(),
90
+ LLMContextPrecisionWithoutReference(),
91
+ ],
92
+ llm=evaluator_llm,
93
+ embeddings=evaluator_embeddings
94
+ )
95
+
96
+ print(results)
97
+ df_results = results.to_pandas()
98
+ df_results.to_csv("evaluation_results.csv", index=False)
99
+ print("Results saved to evaluation_results.csv")
100
+ return results
101
+
102
+
103
+ if __name__ == "__main__":
104
+ df = generate_testset("bando.pdf", num_samples=20)
105
+ print(df[["user_input", "reference"]].head())
106
+ results = evaluate_rag(df, collection_name="bando_recursive")
evaluation_results.csv ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ user_input,retrieved_contexts,response,reference,faithfulness,answer_relevancy,llm_context_precision_without_reference
2
+ What are the key details regarding the Erasmus+ scholarship selection for the academic year 2026/2027?,"[""Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it BANDO DI SELEZIONE PER L'ATTRIBUZIONE DI BORSE DI STUDIO ERASMUS+ PER MOBILITÀ STUDIO PER L’A.A. 2026/2027 (Approvato con D.R. n. 671/2025 del 04/12/2025) Il bando è suddiviso in tre Parti e contiene due Allegati - Parte I - Caratteristiche del Programma Erasmus+ Studio - Parte II - Modalità di partecipazione e di"", 'Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it 03 febbraio 2026 Scadenza per la presentazione della domanda al bando Erasmus+ Studio 2026/2027 (art.5) metà marzo 2026 Pubblicazione delle graduatorie (periodo indicativo) (art. 15) seconda metà di marzo 2026 Accettazione/rifiuto della borsa assegnata, scorrimenti e assegnazioni di sedi residue (periodo indicativo) (artt. 16-17)', 'pagamento delle tasse d’iscrizione presso l’Università ospitante e ricevono un contributo finanziario specifico per la mobilità. Inoltre sono previste ulteriori forme di supporto dal MUR e dall’Ente Regionale per il Diritto allo Studio Universitario (ERDIS – Presidio di Urbino). Art. 2 – Borse di Studio Erasmus+ Per l’a.a. 2026/2027 sono disponibili circa 944 borse di studio, ripartite in base al Dipartimento e alla struttura didattica in cui è inserito il corso di studio (art. 12). Art. 3 – Destinatarie/i', 'Art. 6 – Incompatibilità a) La durata massima di mobilità fisica Erasmus+ è fissata in: - 12 mesi nel I Ciclo (Laurea Triennale); - 12 mesi nel II Ciclo (Laurea Specialistica/Magistrale); - 24 mesi nelle Lauree a Ciclo Unico (Lauree Quinquennali); - 12 mesi nel III Ciclo (Dottorato). Anche i periodi di mobilità non finanziati da fondi dell’Unione Europea sono conteggiati ai fini del computo del numero massimo di mensilità. Presentando domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il', 'domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il candidata/o dichiara di rientrare nei termini massimi di cui sopra. In caso di falsa dichiarazione, la mobilità potrà essere annullata prevedendo la restituzione dei contributi eventualmente erogati. b) Non è inoltre consentito: - ricevere altre borse di studio o finanziamenti dell’Unione Europea. - conseguire il titolo di studio prima della conclusione del periodo di mobilità, pena la decadenza della borsa e la restituzione delle']","The key details regarding the Erasmus+ scholarship selection for the academic year 2026/2027 are as follows:
3
+
4
+ 1. **Application Deadline**: The deadline for submitting applications is February 3, 2026 (Art. 5).
5
+
6
+ 2. **Publication of Rankings**: The rankings are expected to be published in mid-March 2026 (indicative period) (Art. 15).
7
+
8
+ 3. **Acceptance and Refusal of Scholarships**: The acceptance or refusal of the assigned scholarship, including subsequent adjustments and allocations of remaining positions, is anticipated in the second half of March 2026 (indicative period) (Arts. 16-17).
9
+
10
+ 4. **Number of Scholarships**: Approximately 944 scholarships are available, distributed based on the Department and educational structure related to the student's course of study (Art. 12).
11
+
12
+ 5. **Incompatibilities**:
13
+ - The maximum duration of physical mobility is 12 months for the First Cycle (Bachelor), 12 months for the Second Cycle (Master), 24 months for Single Cycle Degrees (Five-Year Degrees), and 12 months for the Third Cycle (Doctorate) (Art. 6).
14
+ - Recipients cannot receive other scholarships or funding from the European Union or obtain their degree before the end of the mobility period, which would result in the loss of the scholarship and the obligation to return any funds received (Art. 6).","The Erasmus+ scholarship selection for the academic year 2026/2027 is detailed in a notice approved with D.R. n. 671/2025 on 04/12/2025. The notice is divided into three parts and includes two attachments, with the first part outlining the characteristics of the Erasmus+ Study Program and the second part detailing the participation methods.",1.0,0.9999995909207617,0.94999999997625
15
+ Cud u plese explane what is Erasmus+ Studio and how long can students participate in it?,"[""Erasmus+ Studio - Parte II - Modalità di partecipazione e di selezione - Parte III - Cosa fare prima, durante e dopo la mobilità Allegato I - Indicazioni aggiuntive per i periodi di mobilità virtuale nell’ambito di mobilità blended Allegato II - Calendario delle scadenze. PARTE I – CARATTERISTICHE DEL PROGRAMMA ERASMUS+ STUDIO Art. 1 – Premessa Il Programma Erasmus+ per Studio offre l'opportunità di trascorrere un periodo compreso tra 2 e 12 mesi (mobilità di lunga durata) o un periodo compreso tra 5 e 30"", 'Art. 6 – Incompatibilità a) La durata massima di mobilità fisica Erasmus+ è fissata in: - 12 mesi nel I Ciclo (Laurea Triennale); - 12 mesi nel II Ciclo (Laurea Specialistica/Magistrale); - 24 mesi nelle Lauree a Ciclo Unico (Lauree Quinquennali); - 12 mesi nel III Ciclo (Dottorato). Anche i periodi di mobilità non finanziati da fondi dell’Unione Europea sono conteggiati ai fini del computo del numero massimo di mensilità. Presentando domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il', ""Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it BANDO DI SELEZIONE PER L'ATTRIBUZIONE DI BORSE DI STUDIO ERASMUS+ PER MOBILITÀ STUDIO PER L’A.A. 2026/2027 (Approvato con D.R. n. 671/2025 del 04/12/2025) Il bando è suddiviso in tre Parti e contiene due Allegati - Parte I - Caratteristiche del Programma Erasmus+ Studio - Parte II - Modalità di partecipazione e di"", ""novità introdotte dalla Programmazione Erasmus+ 2021/2027, qualsiasi periodo di studio all'estero di qualunque durata, compresa la mobilità nell'ambito del dottorato, può essere effettuato sotto forma di mobilità mista. La mobilità mista prevede la combinazione delle attività di mobilità fisica con una componente virtuale che agevola scambi di apprendimento collaborativo e il lavoro di squadra online. Grazie alla componente virtuale, ad esempio, discenti provenienti da paesi e indirizzi di studio diversi"", 'domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il candidata/o dichiara di rientrare nei termini massimi di cui sopra. In caso di falsa dichiarazione, la mobilità potrà essere annullata prevedendo la restituzione dei contributi eventualmente erogati. b) Non è inoltre consentito: - ricevere altre borse di studio o finanziamenti dell’Unione Europea. - conseguire il titolo di studio prima della conclusione del periodo di mobilità, pena la decadenza della borsa e la restituzione delle']","Erasmus+ Studio is a program that offers the opportunity for students to spend a study period abroad, with durations ranging from 2 to 12 months for long-term mobility, or from 5 to 30 months for other types of mobility. Specifically, the maximum duration of physical mobility under Erasmus+ is as follows: 12 months for the I Cycle (Bachelor's Degree), 12 months for the II Cycle (Master's Degree), 24 months for Single Cycle Degrees (Five-Year Degrees), and 12 months for the III Cycle (Doctorate).",Erasmus+ Studio offers the opportunity to spend a period ranging from 2 to 12 months for long-term mobility or a period ranging from 5 to 30.,0.8571428571428571,0.535472838384659,0.99999999995
16
+ Quali opportunità offre la mobilità presso una Università europea per gli studenti?,"['e 12 mesi (mobilità di lunga durata) o un periodo compreso tra 5 e 30 giorni (mobilità di breve durata – ammissibile solo per dottorande/i) presso un’altra Università europea avendo accesso a tutti i servizi offerti alla popolazione studentesca. In mobilità Studio è possibile frequentare attività didattiche, sostenere i relativi esami, svolgere attività di ricerca per tesi o si può effettuare un tirocinio curricolare con la garanzia di riconoscimento delle attività svolte all’interno del proprio piano di', 'opportunità di cui all’art. 8.2 (es. celiachia); - costi per gli accompagnatori necessari per supporto a partecipanti con esigenze fisiche, mentali o sanitarie specifiche. Per precisazioni e richieste inviare una mail all’Ufficio Mobilità Internazionale (studerasmus@uniurb.it oggetto: “Esigenze speciali”). 1 http://ec.europa.eu/programmes/erasmus-plus/tools/distance_en.htm Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029', 'riconoscimento delle attività svolte all’interno del proprio piano di studi. Si consiglia fortemente di programmare la mobilità entro la regolare durata del corso di studi (mentre si è in corso). I Regolamenti dei corsi di studio (o indicazioni per la tesi) prevedono l’attribuzione di un punteggio aggiuntivo al voto di laurea (1760992804Riconoscimenti_punteggiagg_MobilitàErasmus.pdf). Studentesse e studenti in mobilità sono esonerati dal pagamento delle tasse d’iscrizione presso l’Università ospitante e', 'migliorare le competenze linguistiche, la Commissione Europea mette a disposizione di studentesse e studenti Erasmus+ l’“Online Language Support” (OLS). Si tratta di una piattaforma open source che vincitrici e vincitori di borsa Erasmus+ possono utilizzare dal momento del ricevimento delle istruzioni d’accesso e resta a disposizione anche dopo il termine della mobilità. È inoltre possibile utilizzare tale piattaforma per migliorare e approfondire le proprie competenze linguistiche, acquisirne di nuove,', ""che si verifichino durante la mobilità per studio (il dettaglio delle coperture è disponibile alla pagina http://www.uniurb.it/concorsi/10047). Una copertura sanitaria di base viene fornita dal Servizio Sanitario Nazionale anche durante il soggiorno in un altro Paese dell'Unione Europea tramite la Tessera Europea di Assicurazione Malattia (TEAM). Per informazioni sui contenuti della copertura si consiglia di rivolgersi al proprio Distretto Sanitario. Nel caso in cui l’Università ospitante richieda una""]","La mobilità presso un'altra Università europea offre agli studenti la possibilità di frequentare attività didattiche, sostenere esami, svolgere attività di ricerca per la tesi o effettuare un tirocinio curricolare. Inoltre, c'è la garanzia di riconoscimento delle attività svolte all'interno del proprio piano di studi. Durante questo periodo, gli studenti sono esonerati dal pagamento delle tasse d’iscrizione presso l’Università ospitante.","La mobilità presso una Università europea offre opportunità di lunga durata, come un periodo di 12 mesi, o di breve durata, che va da 5 a 30 giorni, ammissibile solo per dottorande/i. Durante la mobilità, gli studenti possono accedere a tutti i servizi offerti alla popolazione studentesca, frequentare attività didattiche, sostenere esami, svolgere attività di ricerca per tesi o effettuare un tirocinio curricolare con la garanzia di riconoscimento delle attività svolte nel proprio piano di studi.",1.0,0.8890087375970701,0.8333333332916666
17
+ Quali sono i vantaggi della mobilità presso l'Università?,"['e 12 mesi (mobilità di lunga durata) o un periodo compreso tra 5 e 30 giorni (mobilità di breve durata – ammissibile solo per dottorande/i) presso un’altra Università europea avendo accesso a tutti i servizi offerti alla popolazione studentesca. In mobilità Studio è possibile frequentare attività didattiche, sostenere i relativi esami, svolgere attività di ricerca per tesi o si può effettuare un tirocinio curricolare con la garanzia di riconoscimento delle attività svolte all’interno del proprio piano di', 'riconoscimento delle attività svolte all’interno del proprio piano di studi. Si consiglia fortemente di programmare la mobilità entro la regolare durata del corso di studi (mentre si è in corso). I Regolamenti dei corsi di studio (o indicazioni per la tesi) prevedono l’attribuzione di un punteggio aggiuntivo al voto di laurea (1760992804Riconoscimenti_punteggiagg_MobilitàErasmus.pdf). Studentesse e studenti in mobilità sono esonerati dal pagamento delle tasse d’iscrizione presso l’Università ospitante e', 'ricevuto a copertura dei giorni di mobilità fisica non effettuata (condizione necessaria per risultare in regola con le tasse al fine del conseguimento del titolo). Non è, inoltre, possibile interrompere la mobilità per sostenere esami in presenza presso l’Università degli Studi di Urbino. È possibile richiedere un’estensione del periodo di mobilità programmata (proroga) secondo le modalità descritte all’art. 24. Art. 8 – Contributi finanziari e requisiti di CFU Art. 8.1 Le borse rappresentano un', 'di mobilità, pena la decadenza della borsa e la restituzione delle eventuali somme ricevute. - svolgere la mobilità presso il proprio Paese di residenza. Art. 7 – Durata di svolgimento della mobilità I soggiorni finanziati nell’ambito del Programma Erasmus+ 2026/2027 devono svolgersi in modo continuativo (senza interruzioni) nell’arco temporale compreso tra l’inizio e la fine delle attività previste dalle Università ospitanti, orientativamente tra il 1° settembre 2026 e il 30 settembre 2027. La durata', 'Mobilità Internazionale scrivendo a studerasmus@uniurb.it e all’Università ospitante secondo le modalità da questa previste. Art. 23 – Durante il periodo di mobilità Studentesse e studenti - una volta giunti a destinazione - sono tenuti a trasmettere all’Ufficio Mobilità Internazionale (studerasmus@uniurb.it) il certificato di frequenza indicante la data di arrivo e sottoscritto dall’Università ospitante. Art. 24 – Estensione del periodo di mobilità/Proroga Eventuali richieste di prolungamento devono']","I vantaggi della mobilità presso l'Università includono:
18
+
19
+ 1. Accesso a tutti i servizi offerti alla popolazione studentesca dell'Università ospitante.
20
+ 2. Possibilità di frequentare attività didattiche, sostenere esami, svolgere attività di ricerca per tesi, o effettuare un tirocinio curricolare con garanzia di riconoscimento delle attività svolte nel proprio piano di studi.
21
+ 3. Esonero dal pagamento delle tasse d’iscrizione presso l’Università ospitante.
22
+ 4. Attribuzione di un punteggio aggiuntivo al voto di laurea, come previsto dai Regolamenti dei corsi di studio.
23
+ 5. Opportunità di richiedere un'estensione del periodo di mobilità programmata.","Le studentesse e studenti in mobilità sono esonerati dal pagamento delle tasse d’iscrizione presso l’Università ospitante, e si consiglia fortemente di programmare la mobilità entro la regolare durata del corso di studi.",1.0,1.0000000000000002,0.99999999995
24
+ What financial support is available for the 2026/2027 academic year?,"['pagamento delle tasse d’iscrizione presso l’Università ospitante e ricevono un contributo finanziario specifico per la mobilità. Inoltre sono previste ulteriori forme di supporto dal MUR e dall’Ente Regionale per il Diritto allo Studio Universitario (ERDIS – Presidio di Urbino). Art. 2 – Borse di Studio Erasmus+ Per l’a.a. 2026/2027 sono disponibili circa 944 borse di studio, ripartite in base al Dipartimento e alla struttura didattica in cui è inserito il corso di studio (art. 12). Art. 3 – Destinatarie/i', 'di mobilità, pena la decadenza della borsa e la restituzione delle eventuali somme ricevute. - svolgere la mobilità presso il proprio Paese di residenza. Art. 7 – Durata di svolgimento della mobilità I soggiorni finanziati nell’ambito del Programma Erasmus+ 2026/2027 devono svolgersi in modo continuativo (senza interruzioni) nell’arco temporale compreso tra l’inizio e la fine delle attività previste dalle Università ospitanti, orientativamente tra il 1° settembre 2026 e il 30 settembre 2027. La durata', 'domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il candidata/o dichiara di rientrare nei termini massimi di cui sopra. In caso di falsa dichiarazione, la mobilità potrà essere annullata prevedendo la restituzione dei contributi eventualmente erogati. b) Non è inoltre consentito: - ricevere altre borse di studio o finanziamenti dell’Unione Europea. - conseguire il titolo di studio prima della conclusione del periodo di mobilità, pena la decadenza della borsa e la restituzione delle', 'Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it 03 febbraio 2026 Scadenza per la presentazione della domanda al bando Erasmus+ Studio 2026/2027 (art.5) metà marzo 2026 Pubblicazione delle graduatorie (periodo indicativo) (art. 15) seconda metà di marzo 2026 Accettazione/rifiuto della borsa assegnata, scorrimenti e assegnazioni di sedi residue (periodo indicativo) (artt. 16-17)', 'potrà a sua insindacabile discrezione decidere di non accettare la studentessa/lo studente Erasmus+; 5. trasmettere all’Ufficio Mobilità Internazionale l’accordo finanziario, ossia il contratto tra Università e studentessa/studente Erasmus+ (inviato orientativamente ad agosto 2026 unitamente ad allegati e istruzioni di compilazione e invio); 6. verificare il livello di copertura assicurativa richiesto dall’Università ospitante; 7. se cittadine/i extra-UE, provvedere autonomamente a ottenere il visto']","For the 2026/2027 academic year, there are approximately 944 Erasmus+ scholarships available, which are allocated based on the Department and the educational structure of the study course (as mentioned in Art. 2). Additionally, students will receive specific financial contributions for mobility, along with further support from the MUR and the Regional Agency for the Right to University Study (ERDIS – Presidio di Urbino).","For the academic year 2026/2027, approximately 944 Erasmus+ scholarships are available, distributed based on the Department and the educational structure in which the study course is included. Additionally, there are specific financial contributions for mobility and further support from the MUR and the Regional Agency for the Right to University Study (ERDIS – Urbino Office).",1.0,0.6321745652920062,0.999999999975
25
+ Quali sono i requisiti per presentare domanda di partecipazione ai Corsi di Laurea Magistrale a Ciclo Unico per l'a.a. 2025/2026?,"['Magistrale a Ciclo Unico d) Corsi di Dottorato di Ricerca (solo per le destinazioni che lo prevedono espressamente) Laureande/i che intendono discutere la tesi nella sessione di laurea straordinaria 2024/2025 e che pertanto non risultano iscritti per l’a.a. 2025/2026, possono presentare domanda di partecipazione purché abbiano effettuato la pre-iscrizione per l’a.a. 2025/2026 a un corso di Laurea Magistrale. In questo caso è necessario fare riferimento alle destinazioni offerte per il corso di', 'cui è inserito il corso di studio (art. 12). Art. 3 – Destinatarie/i Possono presentare domanda di partecipazione coloro che sono regolarmente iscritti per l’a.a. 2025/2026 a: a) Corsi di Laurea Triennale b) Corsi di Laurea Magistrale Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it c) Corsi di Laurea Magistrale a Ciclo Unico d) Corsi di Dottorato di Ricerca (solo per', 'necessario fare riferimento alle destinazioni offerte per il corso di studio/Scuola per il corso di laurea magistrale di preiscrizione. Iscritte/i che prevedono di discutere la propria tesi nella sessione di laurea straordinaria 2025/2026 e che desiderano effettuare la mobilità nell’a.a. 2026/2027, devono essere in regola con l’iscrizione per l’a.a. 2025/2026 e concludere il periodo di mobilità prima del conseguimento del titolo. La mobilità di Dottorande/i deve essere svolta entro il terzo anno del corso', 'Art. 6 – Incompatibilità a) La durata massima di mobilità fisica Erasmus+ è fissata in: - 12 mesi nel I Ciclo (Laurea Triennale); - 12 mesi nel II Ciclo (Laurea Specialistica/Magistrale); - 24 mesi nelle Lauree a Ciclo Unico (Lauree Quinquennali); - 12 mesi nel III Ciclo (Dottorato). Anche i periodi di mobilità non finanziati da fondi dell’Unione Europea sono conteggiati ai fini del computo del numero massimo di mensilità. Presentando domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il', 'Il sistema consente di visualizzare e presentare domanda unicamente per le destinazioni disponibili per la propria Scuola di appartenenza e per il proprio ciclo di studi2, ovvero laurea triennale, laurea magistrale (biennale) o laurea magistrale a ciclo unico (quinquennale). È possibile scegliere da una a cinque destinazioni in ordine di preferenza. Dottorande/i possono presentare domanda unicamente per le destinazioni che ricomprendono il terzo ciclo di studi in una sola delle Scuole affini al Corso di']","Per presentare domanda di partecipazione ai Corsi di Laurea Magistrale a Ciclo Unico per l'a.a. 2025/2026, è necessario essere regolarmente iscritti per l'a.a. 2025/2026 e aver effettuato la pre-iscrizione per l'a.a. 2025/2026 a un corso di Laurea Magistrale. Inoltre, è necessario fare riferimento alle destinazioni offerte per il corso di studio (art. 12).",Possono presentare domanda di partecipazione ai Corsi di Laurea Magistrale a Ciclo Unico coloro che sono regolarmente iscritti per l'a.a. 2025/2026.,1.0,0.9999237003540272,0.94999999997625
26
+ Quali sono i requisiti per la pre-iscrizione ai corsi di Laurea Magistrale per gli studenti che intendono partecipare alla sessione di laurea straordinaria 2024/2025?,"['Magistrale a Ciclo Unico d) Corsi di Dottorato di Ricerca (solo per le destinazioni che lo prevedono espressamente) Laureande/i che intendono discutere la tesi nella sessione di laurea straordinaria 2024/2025 e che pertanto non risultano iscritti per l’a.a. 2025/2026, possono presentare domanda di partecipazione purché abbiano effettuato la pre-iscrizione per l’a.a. 2025/2026 a un corso di Laurea Magistrale. In questo caso è necessario fare riferimento alle destinazioni offerte per il corso di', 'necessario fare riferimento alle destinazioni offerte per il corso di studio/Scuola per il corso di laurea magistrale di preiscrizione. Iscritte/i che prevedono di discutere la propria tesi nella sessione di laurea straordinaria 2025/2026 e che desiderano effettuare la mobilità nell’a.a. 2026/2027, devono essere in regola con l’iscrizione per l’a.a. 2025/2026 e concludere il periodo di mobilità prima del conseguimento del titolo. La mobilità di Dottorande/i deve essere svolta entro il terzo anno del corso', 'cui è inserito il corso di studio (art. 12). Art. 3 – Destinatarie/i Possono presentare domanda di partecipazione coloro che sono regolarmente iscritti per l’a.a. 2025/2026 a: a) Corsi di Laurea Triennale b) Corsi di Laurea Magistrale Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it c) Corsi di Laurea Magistrale a Ciclo Unico d) Corsi di Dottorato di Ricerca (solo per', 'il terzo ciclo di studi in una sola delle Scuole affini al Corso di Dottorato. Verificare con anticipo che le destinazioni offerte siano coerenti con il corso di Dottorato con la/il Referente Erasmus e la/il Coordinatrice/Coordinatore del corso di Dottorato di Ricerca. La domanda di partecipazione prevede l’inserimento dei seguenti allegati: 2 Le/Gli iscritte/i al terzo anno di un corso di Laurea Triennale che intendono partire durante il primo anno di Laurea Magistrale possono presentare domanda per le', 'il primo anno di Laurea Magistrale possono presentare domanda per le destinazioni disponibili per la propria Scuola di afferenza al momento della candidatura e nelle quali sia ricompreso il secondo ciclo di studi. Qualora la/lo studentessa/studente finalizzi l’iscrizione a un corso di Laurea Magistrale afferente a una Scuola diversa, in mancanza di accordi di scambio coerenti per area, numero di posti disponibili e ciclo di studi, perde il diritto alla borsa assegnata. Ufficio Mobilità Internazionale']",Gli studenti laureandi che intendono discutere la tesi nella sessione di laurea straordinaria 2024/2025 e che non risultano iscritti per l’a.a. 2025/2026 possono presentare domanda di partecipazione purché abbiano effettuato la pre-iscrizione per l’a.a. 2025/2026 a un corso di Laurea Magistrale. È necessario fare riferimento alle destinazioni offerte per il corso di studio/Scuola del corso di laurea magistrale di preiscrizione.,Gli studenti laureandi che intendono discutere la tesi nella sessione di laurea straordinaria 2024/2025 e che non risultano iscritti per l’a.a. 2025/2026 possono presentare domanda di partecipazione purché abbiano effettuato la pre-iscrizione per l’a.a. 2025/2026 a un corso di Laurea Magistrale.,1.0,0.7636651573026669,0.94999999997625
27
+ Quali sono i passaggi necessari per completare l'accettazione per mobilità Erasmus e quali sono le conseguenze della mancata presentazione della domanda entro i termini stabiliti?,"['le modalità precisate dall’Ufficio Mobilità Internazionale (“Tutorial presentazione domanda e accettazione per mobilità Erasmus”). Coloro che non completeranno la procedura entro i termini saranno considerati rinunciatarie/i e perderanno ogni diritto alla mobilità e all’eventuale assegnazione delle sedi rimaste disponibili (rinuncia implicita). Art. 17 – Scorrimento della graduatoria e assegnazione delle borse residue Eventuali borse residue in seguito a rinuncia (esplicita o implicita) verranno', 'del 03 febbraio 2026 effettuando i seguenti passaggi: a) accedere alla propria area riservata Esse3; b) cliccare sul link “Mobilità internazionale” e successivamente su “Bandi di mobilità Outgoing”; c) compilare il questionario obbligatorio e procedere con la scelta delle destinazioni preferite (da una a cinque) inserendo i dati richiesti. È inoltre disponibile il “Tutorial presentazione domanda e accettazione per mobilità Erasmus” (http://www.uniurb.it/concorsi/10047). Il sistema consente di visualizzare', 'di un’adeguata competenza linguistica è necessaria ai fini della mobilità Erasmus+. Qualora non si fosse in possesso del livello linguistico richiesto dall’Università assegnata, è necessario che le/i vincitrici/vincitori lo ottengano entro i termini stabiliti dalla stessa superando i test linguistici gratuiti offerti dal CLA (per conoscerne le date e procedere all’iscrizione, si raccomanda di consultare il sito www.cla.uniurb.it)4. Il mancato possesso dei requisiti linguistici richiesti dalle Università', 'possono essere verificate sui siti delle Università Partner. N.B. Le Università Partner possono riservarsi di non accettare la studentessa/lo studente. PARTE III – COSA FARE PRIMA, DURANTE E DOPO LA MOBILITÀ Art. 18 – Prima della partenza Dopo l’accettazione della borsa – e tassativamente prima dell’inizio della mobilità - è necessario: 1. inviare all’Ufficio Mobilità Internazionale l’accordo didattico (learning agreement) e/o l’accordo didattico di ricerca tesi sottoscritto dalla/dal Referente Erasmus di', 'potrà a sua insindacabile discrezione decidere di non accettare la studentessa/lo studente Erasmus+; 5. trasmettere all’Ufficio Mobilità Internazionale l’accordo finanziario, ossia il contratto tra Università e studentessa/studente Erasmus+ (inviato orientativamente ad agosto 2026 unitamente ad allegati e istruzioni di compilazione e invio); 6. verificare il livello di copertura assicurativa richiesto dall’Università ospitante; 7. se cittadine/i extra-UE, provvedere autonomamente a ottenere il visto']","Per completare l'accettazione per mobilità Erasmus, sono necessari i seguenti passaggi:
28
+
29
+ 1. Accedere alla propria area riservata Esse3.
30
+ 2. Cliccare sul link “Mobilità internazionale” e successivamente su “Bandi di mobilità Outgoing”.
31
+ 3. Compilare il questionario obbligatorio e procedere con la scelta delle destinazioni preferite (da una a cinque) inserendo i dati richiesti.
32
+
33
+ Le conseguenze della mancata presentazione della domanda entro i termini stabiliti sono che i partecipanti saranno considerati rinunciatarie/i e perderanno ogni diritto alla mobilità e all’eventuale assegnazione delle sedi rimaste disponibili (rinuncia implicita).","Per completare l'accettazione per mobilità Erasmus, è necessario seguire i passaggi indicati nel tutorial, che includono l'accesso all'area riservata Esse3, cliccare su 'Mobilità internazionale', selezionare 'Bandi di mobilità Outgoing', compilare il questionario obbligatorio e scegliere le destinazioni preferite. Coloro che non completano la procedura entro i termini saranno considerati rinunciatarie/i e perderanno ogni diritto alla mobilità e all'eventuale assegnazione delle sedi rimaste disponibili, con una rinuncia implicita.",1.0,0.8737744501657881,0.9166666666361111
34
+ What are the implications of implicit renunciation on the scholarship amount for Erasmus+ mobility?,"['le modalità precisate dall’Ufficio Mobilità Internazionale (“Tutorial presentazione domanda e accettazione per mobilità Erasmus”). Coloro che non completeranno la procedura entro i termini saranno considerati rinunciatarie/i e perderanno ogni diritto alla mobilità e all’eventuale assegnazione delle sedi rimaste disponibili (rinuncia implicita). Art. 17 – Scorrimento della graduatoria e assegnazione delle borse residue Eventuali borse residue in seguito a rinuncia (esplicita o implicita) verranno', 'borse residue in seguito a rinuncia (esplicita o implicita) verranno riassegnate alle/ai successive/i in graduatoria. L’Ufficio Mobilità Internazionale contatterà tramite e-mail (@campus.uniurb.it) le/gli aventi diritto in base alle destinazioni prescelte, o abbiano fatto richiesta di mobilità per destinazioni residue. Nella comunicazione sarà indicata la scadenza entro la quale confermare la borsa eventualmente assegnata. Le tempistiche dettagliate saranno indicate nel Decreto Rettorale di approvazione', 'domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il candidata/o dichiara di rientrare nei termini massimi di cui sopra. In caso di falsa dichiarazione, la mobilità potrà essere annullata prevedendo la restituzione dei contributi eventualmente erogati. b) Non è inoltre consentito: - ricevere altre borse di studio o finanziamenti dell’Unione Europea. - conseguire il titolo di studio prima della conclusione del periodo di mobilità, pena la decadenza della borsa e la restituzione delle', 'di mobilità, pena la decadenza della borsa e la restituzione delle eventuali somme ricevute. - svolgere la mobilità presso il proprio Paese di residenza. Art. 7 – Durata di svolgimento della mobilità I soggiorni finanziati nell’ambito del Programma Erasmus+ 2026/2027 devono svolgersi in modo continuativo (senza interruzioni) nell’arco temporale compreso tra l’inizio e la fine delle attività previste dalle Università ospitanti, orientativamente tra il 1° settembre 2026 e il 30 settembre 2027. La durata', 'Art. 6 – Incompatibilità a) La durata massima di mobilità fisica Erasmus+ è fissata in: - 12 mesi nel I Ciclo (Laurea Triennale); - 12 mesi nel II Ciclo (Laurea Specialistica/Magistrale); - 24 mesi nelle Lauree a Ciclo Unico (Lauree Quinquennali); - 12 mesi nel III Ciclo (Dottorato). Anche i periodi di mobilità non finanziati da fondi dell’Unione Europea sono conteggiati ai fini del computo del numero massimo di mensilità. Presentando domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il']","Implicit renunciation will result in the loss of all rights to mobility and any potential assignment of remaining available locations. Consequently, any residual scholarships due to such renouncements (explicit or implicit) will be reallocated to the subsequent candidates in the ranking. This implies that individuals who do not complete the procedure within the specified deadlines will not be eligible for the scholarship amounts associated with Erasmus+ mobility.","The implications of implicit renunciation on the scholarship amount for Erasmus+ mobility are significant. If applicants do not complete the procedure within the specified deadlines, they will be considered as having implicitly renounced their rights to mobility and any potential allocation of remaining available positions. Consequently, any remaining scholarships due to such renunciations will be reassigned, affecting the financial support that could have been available to other students.",1.0,0.7934893806302847,0.999999999975
35
+ "What instructions will the International Mobility Office provide regarding the Erasmus+ program, and how does the Online Language Support (OLS) platform assist students in improving their language skills?","['migliorare le competenze linguistiche, la Commissione Europea mette a disposizione di studentesse e studenti Erasmus+ l’“Online Language Support” (OLS). Si tratta di una piattaforma open source che vincitrici e vincitori di borsa Erasmus+ possono utilizzare dal momento del ricevimento delle istruzioni d’accesso e resta a disposizione anche dopo il termine della mobilità. È inoltre possibile utilizzare tale piattaforma per migliorare e approfondire le proprie competenze linguistiche, acquisirne di nuove,', '305327 studerasmus@uniurb.it 2. accertarsi di possedere i requisiti linguistici fissati dall’Università ospitante consultandone il sito Internet o contattando l’Ufficio Erasmus (auspicabilmente già in fase di candidatura), e provvedere se necessario a certificare il proprio livello linguistico anche sostenendo i test previsti dal CLA (cfr. art. 20); 3. sostenere il test di valutazione linguistica online “OLS” prima della mobilità (cfr. art. 21), le istruzioni e l’accesso alla piattaforma saranno forniti', ""accademico in corso in cui poter sostenere la prova di lingua e ottenere l'attestazione Erasmus+: due appelli nei mesi di maggio-giugno, e due appelli nel mese di settembre. Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it Art. 21 – Online Language Support (OLS) della Commissione Europea Al fine di migliorare le competenze linguistiche, la Commissione Europea mette a"", 'approfondire le proprie competenze linguistiche, acquisirne di nuove, anche consultando i forum e interagendo con le community. Le/I vincitrici/vincitori di borsa Erasmus+ devono sostenere un test online di valutazione linguistica nella lingua veicolare della mobilità prima di partire; il risultato del test deve essere successivamente inviato via mail all’Ufficio Mobilità Internazionale (studerasmus@uniurb.it). Ogni eventuale modifica alla modalità di erogazione del test OLS apportata dall’ente di', 'alla modalità di erogazione del test OLS apportata dall’ente di riferimento, incluso il link alla piattaforma, sarà tempestivamente comunicata all’account di posta istituzionale. Per ulteriori informazioni consultare il sito https://academy.europa.eu/. Art. 22 – Rinuncia al periodo di mobilità In caso di rinuncia successiva all’accettazione di cui all’art. 16, studentesse e studenti devono darne tempestiva comunicazione mail all’Ufficio Mobilità Internazionale scrivendo a studerasmus@uniurb.it e']","The International Mobility Office will provide instructions and access to the Online Language Support (OLS) platform for students who have been awarded an Erasmus+ scholarship. The OLS platform assists students in improving their language skills by allowing them to use it from the moment they receive access instructions and even after their mobility period ends. It offers opportunities to enhance and deepen language competencies, acquire new skills, and interact with forums and communities.
36
+
37
+ Additionally, students must take an online language assessment test in the language of instruction before their mobility, and the result must be emailed to the International Mobility Office. Any changes to the test administration will be communicated to students via their institutional email account.","The International Mobility Office will provide instructions and access to the platform starting from June 2026, which students must follow carefully for enrollment at the host university. Additionally, the Erasmus+ program offers the Online Language Support (OLS) platform, which students can use to improve their language skills from the moment they receive access instructions and continues to be available even after their mobility period.",0.9,0.8088735684511121,0.99999999998
38
+ Quali sono i requisiti e i servizi agli studenti che devono essere considerati per l'iscrizione presso l'Università ospitante secondo le istruzioni fornite dall'Ufficio Mobilità Internazionale?,"['art. 21), le istruzioni e l’accesso alla piattaforma saranno forniti dall’Ufficio Mobilità Internazionale orientativamente a partire da giugno 2026; 4. provvedere all’iscrizione presso l’Università ospitante attenendosi scrupolosamente alle istruzioni da questa inviate. In caso di mancato invio della documentazione richiesta e/o del mancato possedimento dei requisiti posti entro la scadenza fissata dall’Università ospitante, questa potrà a sua insindacabile discrezione decidere di non accettare la', 'Mobilità Internazionale scrivendo a studerasmus@uniurb.it e all’Università ospitante secondo le modalità da questa previste. Art. 23 – Durante il periodo di mobilità Studentesse e studenti - una volta giunti a destinazione - sono tenuti a trasmettere all’Ufficio Mobilità Internazionale (studerasmus@uniurb.it) il certificato di frequenza indicante la data di arrivo e sottoscritto dall’Università ospitante. Art. 24 – Estensione del periodo di mobilità/Proroga Eventuali richieste di prolungamento devono', 'l’Ateneo di Urbino. Al momento della presentazione della candidatura studentesse/studenti devono verificare che le Università selezionate garantiscano un’offerta formativa coerente con il proprio piano di studi. Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it L’accordo didattico per la meta assegnata è compilabile online, seguendo le istruzioni riportate nella “Guida', 'Tel. +39 0722 305327 studerasmus@uniurb.it Art. 25 – Al termine della mobilità Al termine definitivo del periodo di mobilità, studentesse e studenti devono consegnare all’Ufficio Mobilità Internazionale, tassativamente entro e non oltre ottobre 2027, i seguenti documenti: 1. certificato di frequenza attestante le date di inizio e fine mobilità sottoscritto dall’Università ospitante, in originale e senza correzioni (in alternativa il documento può essere accettato via mail purché inviato direttamente', 'tra l’Istituto e la/lo studentessa/studente. Non sono ammesse interruzioni o sospensioni del periodo di studi (es. non si può chiedere il prolungamento durante i mesi estivi per la sessione di esami a settembre se in tale periodo non sono previste attività didattiche dall’Università ospitante). Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it Art. 25 – Al termine della']","I requisiti per l'iscrizione presso l'Università ospitante includono il possesso della documentazione richiesta e il soddisfacimento dei requisiti posti dall'Università ospitante entro la scadenza fissata. Inoltre, le studentesse e gli studenti devono verificare che le Università selezionate garantiscano un'offerta formativa coerente con il proprio piano di studi. I servizi agli studenti sono forniti dall'Ufficio Mobilità Internazionale, che offre istruzioni e supporto via email a studerasmus@uniurb.it.","Per l'iscrizione presso l'Università ospitante, è fondamentale attenersi scrupolosamente alle istruzioni inviate dall'Ufficio Mobilità Internazionale. In caso di mancato invio della documentazione richiesta o del mancato possedimento dei requisiti entro la scadenza fissata, l'Università ospitante potrà decidere di non accettare lo studente. Inoltre, le assenze di CFU conseguiti all'estero saranno esaminate dalla Commissione Erasmus, e qualsiasi impossibilità deve essere documentata e segnalata all'Ufficio Mobilità Internazionale.",1.0,0.7883354109274944,0.999999999975
39
+ What is the deadline for submitting scholarship applications and what are the mobility requirements for students?,"['può essere presentata a partire dalla data di pubblicazione del presente bando e fino alle ore 12:00 del 03 febbraio 2026 (cfr. art. 10). Sono ammesse/i solo coloro che risultano in regola con il versamento delle tasse per l’intero periodo della mobilità. Il possesso di una buona conoscenza della lingua del Paese di destinazione è un requisito indispensabile per effettuare la mobilità. Il livello linguistico richiesto dall’Università di destinazione dovrà essere certificato prima della partenza (cfr. art.', 'da apposito Bando, a cura dei Dipartimenti interessati, in raccordo con l’Ufficio Mobilità Internazionale. I Bandi vengono pubblicati nella sezione International e nel sito dei Dipartimenti. Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it Art. 5 – Presentazione della candidatura La domanda di mobilità può essere presentata a partire dalla data di pubblicazione del', 'Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it 03 febbraio 2026 Scadenza per la presentazione della domanda al bando Erasmus+ Studio 2026/2027 (art.5) metà marzo 2026 Pubblicazione delle graduatorie (periodo indicativo) (art. 15) seconda metà di marzo 2026 Accettazione/rifiuto della borsa assegnata, scorrimenti e assegnazioni di sedi residue (periodo indicativo) (artt. 16-17)', 'dettagliate saranno indicate nel Decreto Rettorale di approvazione della graduatoria. Art. 17.1 – Comunicazione nominativi alle Università Partner da parte di Uniurb Dopo l’assegnazione delle borse di mobilità, l’Università comunicherà i nominativi (nomination) alle Università di destinazione. L’Università di destinazione, secondo le proprie tempistiche interne, invierà poi a studentesse e studenti le procedure di iscrizione e ammissione (application). Gli Atenei Partner accettano le nomination delle/dei', 'viene richiesto per un intero semestre aggiuntivo (o altro documento giustificativo, per es. calendario accademico se il prolungamento viene richiesto per il completamento della sessione d’esame). Entrambi i documenti devono essere inviati già firmati per accettazione dall’Università ospitante. L’Ufficio Mobilità Internazionale comunicherà via e-mail l’accettazione della richiesta di prolungamento attraverso apposita lettera di notifica tra l’Istituto e la/lo studentessa/studente. Non sono ammesse']","The deadline for submitting scholarship applications is until 12:00 on February 3, 2026 (cfr. art. 10). The mobility requirements for students include being in good standing with tax payments for the entire mobility period and possessing a good knowledge of the language of the destination country, which must be certified before departure.","The deadline for submitting scholarship applications is until 12:00 PM on February 3, 2026. To be eligible for mobility, applicants must be in good standing with their tuition payments for the entire mobility period and possess a good knowledge of the language of the destination country, which must be certified before departure.",1.0,0.9148017329124937,0.9999999999
40
+ Che cosa fa la Commissione di valutazione quando c'è una richiesta di prolungamento?,"['di mobilità/Proroga Eventuali richieste di prolungamento devono essere presentate all’Ufficio Mobilità Internazionale almeno un mese prima della fine del periodo di studio concordato nell’accordo finanziario inviando i seguenti documenti: 1. modulo di richiesta prolungamento (disponibile alla pagina https://www.uniurb.it/international/mobilitaandare-all-estero/studenti); 2. accordo didattico per il secondo semestre se il prolungamento viene richiesto per un intero semestre aggiuntivo (o altro documento', 'viene richiesto per un intero semestre aggiuntivo (o altro documento giustificativo, per es. calendario accademico se il prolungamento viene richiesto per il completamento della sessione d’esame). Entrambi i documenti devono essere inviati già firmati per accettazione dall’Università ospitante. L’Ufficio Mobilità Internazionale comunicherà via e-mail l’accettazione della richiesta di prolungamento attraverso apposita lettera di notifica tra l’Istituto e la/lo studentessa/studente. Non sono ammesse', 'svolgere nella sede prescelta (per una o più sedi). c) Certificazioni linguistiche (opzionale) – max. 4 punti: possesso di documentate certificazioni linguistiche già in fase di candidatura. I documenti di cui ai punti a), b) e c) devono essere allegati in fase di presentazione della candidatura (cfr. art. 10). In mancanza di documentazione il punteggio non verrà attribuito. La Commissione di valutazione si riserva la possibilità di convocare le/i candidate/i per un colloquio conoscitivo prima della', 'e studenti decidono a propria discrezione se presentare il piano per una o più sedi). c) Certificazioni linguistiche (opzionale) – max. 3 punti: possesso di documentate certificazioni linguistiche già in fase di candidatura. I documenti di cui ai punti a), b) e c) devono essere allegati in fase di presentazione della candidatura (cfr. art. 10). In mancanza di documentazione il punteggio non verrà attribuito. Scuola di Economia: la Commissione di valutazione si riserva di convocare per un colloquio', 'della candidatura. Il titolo di studio può essere integrato anche successivamente alla scadenza del presente bando purché in tempi utili e comunque entro la riunione della Commissione. In mancanza di tale segnalazione non vi potrà essere assegnazione di punteggio. Il titolo di studio deve essere in ogni caso conseguito e integrato entro la partenza, pena la revoca della borsa Erasmus e la restituzione delle eventuali somme ricevute. Per coloro che abbiano conseguito il titolo di studio all’estero, si fa']",La Commissione di valutazione si riserva la possibilità di convocare le/i candidate/i per un colloquio conoscitivo prima della valutazione della candidatura. Questo è indicato nel contesto riguardante le richieste di prolungamento.,"La Commissione di valutazione si riserva di convocare per un colloquio studentesse e studenti del doppio titolo qualora il numero delle candidature pervenute superi il numero dei posti disponibili. Inoltre, per una richiesta di prolungamento, è necessario inviare documenti firmati per accettazione dall'Università ospitante, e l'Ufficio Mobilità Internazionale comunicherà via e-mail l'accettazione della richiesta.",0.3333333333333333,0.5280049065906045,0.3333333333
41
+ "What instructions will the Ufficio Mobilità Internazionale provide regarding the enrollment process at the host university, and how should students prepare their educational activities for their selected destinations?","['art. 21), le istruzioni e l’accesso alla piattaforma saranno forniti dall’Ufficio Mobilità Internazionale orientativamente a partire da giugno 2026; 4. provvedere all’iscrizione presso l’Università ospitante attenendosi scrupolosamente alle istruzioni da questa inviate. In caso di mancato invio della documentazione richiesta e/o del mancato possedimento dei requisiti posti entro la scadenza fissata dall’Università ospitante, questa potrà a sua insindacabile discrezione decidere di non accettare la', 'Mobilità Internazionale scrivendo a studerasmus@uniurb.it e all’Università ospitante secondo le modalità da questa previste. Art. 23 – Durante il periodo di mobilità Studentesse e studenti - una volta giunti a destinazione - sono tenuti a trasmettere all’Ufficio Mobilità Internazionale (studerasmus@uniurb.it) il certificato di frequenza indicante la data di arrivo e sottoscritto dall’Università ospitante. Art. 24 – Estensione del periodo di mobilità/Proroga Eventuali richieste di prolungamento devono', 'potrà a sua insindacabile discrezione decidere di non accettare la studentessa/lo studente Erasmus+; 5. trasmettere all’Ufficio Mobilità Internazionale l’accordo finanziario, ossia il contratto tra Università e studentessa/studente Erasmus+ (inviato orientativamente ad agosto 2026 unitamente ad allegati e istruzioni di compilazione e invio); 6. verificare il livello di copertura assicurativa richiesto dall’Università ospitante; 7. se cittadine/i extra-UE, provvedere autonomamente a ottenere il visto', 'possono essere verificate sui siti delle Università Partner. N.B. Le Università Partner possono riservarsi di non accettare la studentessa/lo studente. PARTE III – COSA FARE PRIMA, DURANTE E DOPO LA MOBILITÀ Art. 18 – Prima della partenza Dopo l’accettazione della borsa – e tassativamente prima dell’inizio della mobilità - è necessario: 1. inviare all’Ufficio Mobilità Internazionale l’accordo didattico (learning agreement) e/o l’accordo didattico di ricerca tesi sottoscritto dalla/dal Referente Erasmus di', 'del 03 febbraio 2026 effettuando i seguenti passaggi: a) accedere alla propria area riservata Esse3; b) cliccare sul link “Mobilità internazionale” e successivamente su “Bandi di mobilità Outgoing”; c) compilare il questionario obbligatorio e procedere con la scelta delle destinazioni preferite (da una a cinque) inserendo i dati richiesti. È inoltre disponibile il “Tutorial presentazione domanda e accettazione per mobilità Erasmus” (http://www.uniurb.it/concorsi/10047). Il sistema consente di visualizzare']","The Ufficio Mobilità Internazionale will provide instructions and access to the platform starting approximately in June 2026 for the enrollment process at the host university. Students must scrupulously adhere to the instructions sent by the host university. Additionally, before the start of mobility and after acceptance of the scholarship, students are required to send the learning agreement and/or the thesis research agreement signed by the Erasmus Referent to the Ufficio Mobilità Internazionale. They must also access their reserved area on Esse3, click on ""Mobilità internazionale,"" then ""Bandi di mobilità Outgoing,"" and complete the mandatory questionnaire while selecting their preferred destinations (from one to five) by entering the requested data.","The Ufficio Mobilità Internazionale will provide instructions and access to the platform starting approximately in June 2026. Students must ensure they enroll at the host university by strictly following the instructions sent by the university. Additionally, it is strongly recommended that students prepare a plan of educational activities to be carried out abroad for each selected destination during the application phase, in order to preliminarily verify the actual offerings of activities available.",1.0,0.6765086479376171,0.8041666666465626
42
+ What services does the Dipartimento di Scienze offer to students in Urbino?,"[""Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it DISPEA Scienze Geologiche e Ambientali 16 Informatica Applicata 24 Filosofia dell'Informazione 10 *Numero indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Il Dipartimento di Scienze"", 'Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it Il Dipartimento di Scienze Biomolecolari attribuisce il punteggio aggiuntivo secondo i seguenti criteri: a) Lettera motivazionale (obbligatoria) – max. 4 punti: predisposizione di una lettera motivazionale (max. 2.000 caratteri, spazi inclusi) che descriva la scelta dell’esperienza e della sede evidenziando la congruità dell’offerta formativa della stessa con il proprio curriculum di studi. Sono valutate', 'Molecolare, Sanitaria e della Nutrizione 24 Scienze Biologiche, Biotecnologie 51 Scienze Motorie 42 *Numero indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39', 'l’Ateneo di Urbino. Al momento della presentazione della candidatura studentesse/studenti devono verificare che le Università selezionate garantiscano un’offerta formativa coerente con il proprio piano di studi. Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it L’accordo didattico per la meta assegnata è compilabile online, seguendo le istruzioni riportate nella “Guida', 'I documenti di cui al punto a) e b) vanno allegati in fase di presentazione della candidatura (cfr. art. 10). In mancanza di documentazione il punteggio non verrà attribuito. Art. 12.5 – Dipartimento di Scienze Pure e Applicate (DISPeA) Risultano disponibili circa 66 borse di studio, così ripartite: DIPARTIMENTO SCUOLA / CORSO DI LAUREA NUMERO BORSE* DISPEA Conservazione e Restauro 16 Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 -']",This information is not found in the provided document.,"The Dipartimento di Scienze, located at Palazzo Bonaventura in Urbino, provides various services to students, including support for academic and research activities. However, specific details about the services offered are not provided in the context.",0.0,0.0,0.0
43
+ Quali documenti devono essere consegnati all’Ufficio Mobilità Internazionale entro ottobre 2027?,"['Tel. +39 0722 305327 studerasmus@uniurb.it Art. 25 – Al termine della mobilità Al termine definitivo del periodo di mobilità, studentesse e studenti devono consegnare all’Ufficio Mobilità Internazionale, tassativamente entro e non oltre ottobre 2027, i seguenti documenti: 1. certificato di frequenza attestante le date di inizio e fine mobilità sottoscritto dall’Università ospitante, in originale e senza correzioni (in alternativa il documento può essere accettato via mail purché inviato direttamente', 'dei singoli Corsi di Studio di afferenza. La richiesta di convalida delle attività formative svolte all’estero va inoltrata all’Ufficio Mobilità Internazionale entro ottobre 2027. Art. 26 – Questionario di valutazione/Participant Report (EU Survey) Al termine del periodo di mobilità, le/i partecipanti riceveranno il link al questionario obbligatorio di valutazione dell’esperienza di mobilità, da compilare e trasmettere entro e non oltre i 30 giorni successivi al ricevimento della richiesta. In caso di', 'di mobilità/Proroga Eventuali richieste di prolungamento devono essere presentate all’Ufficio Mobilità Internazionale almeno un mese prima della fine del periodo di studio concordato nell’accordo finanziario inviando i seguenti documenti: 1. modulo di richiesta prolungamento (disponibile alla pagina https://www.uniurb.it/international/mobilitaandare-all-estero/studenti); 2. accordo didattico per il secondo semestre se il prolungamento viene richiesto per un intero semestre aggiuntivo (o altro documento', 'Mobilità Internazionale scrivendo a studerasmus@uniurb.it e all’Università ospitante secondo le modalità da questa previste. Art. 23 – Durante il periodo di mobilità Studentesse e studenti - una volta giunti a destinazione - sono tenuti a trasmettere all’Ufficio Mobilità Internazionale (studerasmus@uniurb.it) il certificato di frequenza indicante la data di arrivo e sottoscritto dall’Università ospitante. Art. 24 – Estensione del periodo di mobilità/Proroga Eventuali richieste di prolungamento devono', 'viene richiesto per un intero semestre aggiuntivo (o altro documento giustificativo, per es. calendario accademico se il prolungamento viene richiesto per il completamento della sessione d’esame). Entrambi i documenti devono essere inviati già firmati per accettazione dall’Università ospitante. L’Ufficio Mobilità Internazionale comunicherà via e-mail l’accettazione della richiesta di prolungamento attraverso apposita lettera di notifica tra l’Istituto e la/lo studentessa/studente. Non sono ammesse']","Entro ottobre 2027, gli studenti devono consegnare all'Ufficio Mobilità Internazionale i seguenti documenti:
44
+
45
+ 1. Certificato di frequenza attestante le date di inizio e fine mobilità, sottoscritto dall'Università ospitante, in originale e senza correzioni (in alternativa, il documento può essere accettato via mail purché inviato direttamente).
46
+ 2. Richiesta di convalida delle attività formative svolte all'estero.","Entro ottobre 2027, le studentesse e gli studenti devono consegnare all’Ufficio Mobilità Internazionale un certificato di frequenza attestante le date di inizio e fine mobilità, sottoscritto dall’Università ospitante, in originale e senza correzioni. In alternativa, il documento può essere accettato via mail purché inviato direttamente.",0.8333333333333334,0.9432177739798169,0.9166666666361111
47
+ What are the funding norms applicable to mobility activities for higher education as outlined by the Commissione Europea?,"['EUR 580 EUR 4000-7999 km 1188 EUR 1188 EUR 8000km o più 1735 EUR 1735 EUR (1) Tabella A “Norme di finanziamento applicabili a tutte le attività di mobilità per l’Istruzione Superiore” (Guida del Programma 2025) La fascia chilometrica per il calcolo del contributo ai costi di viaggio A/R è individuata attraverso il calcolatore di distanza della Commissione Europea1. L’intervallo chilometrico tiene conto di una singola tratta in cui il punto di partenza è l’Istituzione di invio del partecipante e quello di', ""non sono ammissibili al finanziamento. Il contributo finanziario viene calcolato ed erogato solo sulla base dei giorni di mobilità fisica (svolti in presenza presso il Paese ospitante). 2.2 Le mobilità di studentesse e studenti che si recano nel Paese ospitante per seguire attività virtuali sono ammissibili al pieno finanziamento. L'effettiva presenza presso il Paese ospitante sarà confermata dall'Istituto di destinazione tramite la documentazione usuale, quale certificato di frequenza e/o transcript of"", 'Art. 6 – Incompatibilità a) La durata massima di mobilità fisica Erasmus+ è fissata in: - 12 mesi nel I Ciclo (Laurea Triennale); - 12 mesi nel II Ciclo (Laurea Specialistica/Magistrale); - 24 mesi nelle Lauree a Ciclo Unico (Lauree Quinquennali); - 12 mesi nel III Ciclo (Dottorato). Anche i periodi di mobilità non finanziati da fondi dell’Unione Europea sono conteggiati ai fini del computo del numero massimo di mensilità. Presentando domanda di candidatura al bando Erasmus+ Studio a.a. 2026/2027, la/il', 'migliorare le competenze linguistiche, la Commissione Europea mette a disposizione di studentesse e studenti Erasmus+ l’“Online Language Support” (OLS). Si tratta di una piattaforma open source che vincitrici e vincitori di borsa Erasmus+ possono utilizzare dal momento del ricevimento delle istruzioni d’accesso e resta a disposizione anche dopo il termine della mobilità. È inoltre possibile utilizzare tale piattaforma per migliorare e approfondire le proprie competenze linguistiche, acquisirne di nuove,', ""accademico in corso in cui poter sostenere la prova di lingua e ottenere l'attestazione Erasmus+: due appelli nei mesi di maggio-giugno, e due appelli nel mese di settembre. Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it Art. 21 – Online Language Support (OLS) della Commissione Europea Al fine di migliorare le competenze linguistiche, la Commissione Europea mette a""]","The funding norms applicable to mobility activities for higher education, as outlined by the Commissione Europea, are specified in Tabella A “Norme di finanziamento applicabili a tutte le attività di mobilità per l’Istruzione Superiore” (Guida del Programma 2025). The financial contribution for travel costs is calculated based on the distance calculator of the European Commission, with specific funding amounts depending on the distance traveled (e.g., EUR 580 for distances up to 3999 km, EUR 1188 for distances between 4000-7999 km, and EUR 1735 for distances of 8000 km or more). The financial contribution is only provided for physical mobility days spent in the host country, while students attending virtual activities are eligible for full funding.","The funding norms applicable to mobility activities for higher education, as outlined by the Commissione Europea, include a distance-based contribution for travel costs. The contribution is calculated based on the distance between the sending institution and the destination, with specific funding amounts assigned to different distance ranges, such as EUR 580 for distances between 4000-7999 km and EUR 1188 for distances of 8000 km or more.",1.0,0.9888607599991852,0.99999999995
48
+ "What criteria do the Dipartimenti use to assign scores for scholarship applications, and how do these relate to the Blended Intensive Programme (BIP) opportunities available to students?","['Blended Intensive Programme (BIP) Alcuni corsi di studio/Dipartimenti implementano programmi di Mobilità BIP (Blended Intensive Programme), ai quali studentesse/studenti iscritti ai corsi possono partecipare. Le Mobilità BIP sono mobilità di breve periodo (1-2 settimane) che prevedono la partecipazione a un programma “intensivo” e comportano l’acquisizione di un massimo di 3 CFU. La partecipazione ai Programmi di Mobilità BIP è regolamentata da apposito Bando, a cura dei Dipartimenti interessati, in', 'variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Il Dipartimento di Economia, Società e Politica attribuisce il punteggio aggiuntivo secondo i seguenti criteri: a) Lettera motivazionale (opzionale) – max. 4 punti: predisposizione di una lettera motivazionale (max. 2.000 caratteri, spazi inclusi) che descriva la scelta dell’esperienza e', 'possibilità di effettuare attività di ricerca tesi nell’Università di interesse già in fase di candidatura, per evitare, in caso di selezione, di dover successivamente rinunciare/rimodulare la mobilità. L’attività di preparazione della tesi di Laurea o di Dottorato non è possibile in tutte le sedi e/o è possibile solo se abbinata alla frequenza di corsi, e deve essere autorizzata in via preventiva dal Collegio dei Docenti/Coordinatore. Blended Intensive Programme (BIP) Alcuni corsi di studio/Dipartimenti', 'indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Il Dipartimento di Studi Umanistici attribuisce il punteggio aggiuntivo secondo i seguenti criteri: Lettera motivazionale (opzionale) – max. 10 punti: predisposizione di una lettera motivazionale (min. 1.000 e max. 2.000 caratteri, spazi inclusi) che sostanzi la', 'verranno presi in considerazione. Art. 11 – Criteri di selezione e valutazione delle domande La selezione delle candidature è effettuata per ciascun ambito di studi da una Commissione, nominata con Decreto Rettorale. Le Commissioni delle Strutture didattiche attribuiscono il punteggio fino a un massimo di 40 punti, sulla base del “merito” (voti di maturità/laurea o media di carriera) (a) e di un eventuale punteggio aggiuntivo (b) assegnato dai singoli Dipartimenti/dalle singole Scuole (art. 12). Il']","The Dipartimenti use the following criteria to assign scores for scholarship applications related to the Blended Intensive Programme (BIP):
49
+
50
+ 1. **Merit**: This is based on academic performance, specifically the voti di maturità/laurea or media di carriera (Article 11).
51
+ 2. **Additional Points**: Each Dipartimento can assign additional points based on specific criteria:
52
+ - For the Dipartimento di Economia, Società e Politica, a letter motivazionale (optional) can earn a maximum of 4 points.
53
+ - For the Dipartimento di Studi Umanistici, a letter motivazionale (optional) can earn a maximum of 10 points.
54
+
55
+ The preparation of a letter motivazionale is encouraged as it can enhance the application score, and students are advised to consider the possibility of conducting research for their thesis at the host University during their application process to avoid later complications.","The Dipartimenti assign scores for scholarship applications based on merit, with a maximum of 30 points out of 40 attributed according to the maturity exam score. For first-year students in a Bachelor's or Master's program, the parameters are calculated based on their maturity exam scores, with specific points assigned for different score ranges. Additionally, some Dipartimenti implement Blended Intensive Programme (BIP) opportunities, which are short-term mobility programs lasting 1-2 weeks, allowing students to participate in intensive programs and earn up to 3 CFU. The participation in these BIP programs is regulated by specific announcements from the relevant Dipartimenti.",0.7142857142857143,0.9178020968117492,0.99999999998
56
+ Che punteggio si attribuisce per il merito dai Dipartimenti per gli studenti iscritti al primo anno?,"['assegnato dai singoli Dipartimenti/dalle singole Scuole (art. 12). Il punteggio è attribuito nel rispetto dei seguenti parametri (a+b): a) punteggio in base al “merito” (massimo 30 punti su 40): - per iscritte/i al primo anno di un Corso di Laurea Triennale o Magistrale a Ciclo Unico, i parametri sono calcolati sulla base del voto di maturità, secondo il prospetto di seguito riportato: Voto di Maturità Punteggio 100 e lode 25 96-100 24 91-95 21 81-90 18 71-80 15 60-70 12 - per iscritte/i al primo anno di', 'verranno presi in considerazione. Art. 11 – Criteri di selezione e valutazione delle domande La selezione delle candidature è effettuata per ciascun ambito di studi da una Commissione, nominata con Decreto Rettorale. Le Commissioni delle Strutture didattiche attribuiscono il punteggio fino a un massimo di 40 punti, sulla base del “merito” (voti di maturità/laurea o media di carriera) (a) e di un eventuale punteggio aggiuntivo (b) assegnato dai singoli Dipartimenti/dalle singole Scuole (art. 12). Il', 'elettronico (Esse3). Verranno tenuti in considerazione gli esami verbalizzati entro il 31 dicembre 2025. Non rientrano pertanto eventuali attività didattiche registrate in data successiva. La formula utilizzata dal sistema è la seguente: 0,8 * media voti studente + 0,2 * (30 * crediti acquisiti/crediti previsti nell’anno di iscrizione); b) punteggio “aggiuntivo” (massimo 10 punti su 40): tale punteggio è attribuito nel rispetto della ripartizione indicata da ciascun Dipartimento (art. 12). Ufficio Mobilità', '91-95 21 81-90 18 71-80 15 60-70 12 - per iscritte/i al primo anno di un Corso di Laurea Magistrale e per dottorande/i, i parametri sono calcolati sulla base del voto di Laurea (Triennale nel primo caso, Magistrale nel secondo caso), seguendo il prospetto sotto riportato: Voto di Laurea Punteggio 110 lode 27.0 110 26.5 109 26.2 108 26.0 107 25.7 106 25.5 105 25.2 Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT', 'indicata da ciascun Dipartimento (art. 12). Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it Art. 12 – Borse disponibili e criteri per l’attribuzione del punteggio aggiuntivo Oltre al punteggio basato sul merito (art. 11 punto a)), ogni Dipartimento/Scuola/Corso di Laurea ha definito i criteri e le modalità ai fini dell’assegnazione di un punteggio “aggiuntivo” (massimo']","Per gli studenti iscritti al primo anno di un Corso di Laurea Triennale o Magistrale a Ciclo Unico, il punteggio attribuito per il merito è calcolato sulla base del voto di maturità, con i seguenti valori:
57
+
58
+ - Voto di Maturità 100 e lode: 25 punti
59
+ - Voto di Maturità 96-100: 24 punti
60
+ - Voto di Maturità 91-95: 21 punti
61
+ - Voto di Maturità 81-90: 18 punti
62
+ - Voto di Maturità 71-80: 15 punti
63
+ - Voto di Maturità 60-70: 12 punti
64
+
65
+ Il punteggio massimo per il merito è di 30 punti su 40 (art. 11).","Il punteggio attribuito dai Dipartimenti per il merito agli studenti iscritti al primo anno di un Corso di Laurea Triennale o Magistrale a Ciclo Unico è massimo 30 punti su 40, calcolato sulla base del voto di maturità. Ad esempio, un voto di maturità di 100 e lode riceve 25 punti, mentre un voto tra 96 e 100 riceve 24 punti.",1.0,0.8228854411975927,0.9166666666361111
66
+ What are the available scholarship opportunities in the field of Scienze Biologiche and how are they distributed among different programs?,"['convocare le/i candidate/i per un colloquio conoscitivo prima della pubblicazione finale delle graduatorie di merito con relativa assegnazione delle sedi ospitanti, anche al fine di valutare la relativa motivazione. Art. 12.3 – Dipartimento di Scienze Biomolecolari (DISB) Risultano disponibili circa 170 borse di studio, così ripartite: DIPARTIMENTO SCUOLA / CORSO DI LAUREA NUMERO BORSE* DISB Farmacia, CTF 53 Scienze della Nutrizione, Biologia Molecolare, Sanitaria e della Nutrizione 24 Scienze Biologiche,', 'Molecolare, Sanitaria e della Nutrizione 24 Scienze Biologiche, Biotecnologie 51 Scienze Motorie 42 *Numero indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39', 'I documenti di cui al punto a) e b) vanno allegati in fase di presentazione della candidatura (cfr. art. 10). In mancanza di documentazione il punteggio non verrà attribuito. Art. 12.5 – Dipartimento di Scienze Pure e Applicate (DISPeA) Risultano disponibili circa 66 borse di studio, così ripartite: DIPARTIMENTO SCUOLA / CORSO DI LAUREA NUMERO BORSE* DISPEA Conservazione e Restauro 16 Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 -', 'Umanistici e Internazionali (DISCUI) Risultano disponibili circa 220 borse di studio, così ripartite: DIPARTIMENTO SCUOLA / CORSO DI LAUREA NUMERO BORSE* DISCUI Lingue e Letterature Straniere 166 Lingue e Letterature Straniere (Progetto “Eurocampus”) 5 Scienze della Comunicazione 49 *Numero indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di', 'ai punti a), b) e c) vanno allegati in fase di presentazione della candidatura (cfr. art. 10). In mancanza di documentazione il punteggio non verrà attribuito. Art. 12.6 – Dipartimento di Studi Umanistici (DISTUM) Risultano disponibili circa 183 borse di studio, così ripartite: DIPARTIMENTO SCUOLA / CORSO DI LAUREA NUMERO BORSE* DISTUM Lettere, Arti, Filosofia – Storia dell’Arte 72 Psicologia 40 Scienze della Formazione 71 *Numero indicativo che potrebbe variare entro la chiusura del bando e/o se le']","In the field of Scienze Biologiche, there are approximately 24 scholarships available in the programs ""Scienze Biologiche, Molecolare, Sanitaria e della Nutrizione"" and 51 scholarships in ""Scienze Biologiche, Biotecnologie."" Thus, the total available scholarships in this field amount to 75, distributed as follows:
67
+
68
+ - Scienze Biologiche, Molecolare, Sanitaria e della Nutrizione: 24 scholarships
69
+ - Scienze Biologiche, Biotecnologie: 51 scholarships","In the field of Scienze Biologiche, there are approximately 170 scholarships available. These are distributed as follows: 24 scholarships for Scienze della Nutrizione, Biologia Molecolare, Sanitaria e della Nutrizione, and 51 scholarships for Biotecnologie. Additionally, there are 42 scholarships for Scienze Motorie. The number of scholarships may vary until the closing of the call for applications or if partner universities make changes to the agreements.",1.0,0.8283489554829295,0.9999999999666667
70
+ Cosa fa il Dipartimento di Scienze Pure e Applicate per l'implementazione dell'Erasmus Without Paper?,"['implementazione (Erasmus Without Paper). Il Dipartimento di Scienze Pure e Applicate attribuisce il punteggio aggiuntivo secondo i seguenti criteri: a) Lettera motivazionale (opzionale) – max. 4 punti: predisposizione di una lettera motivazionale (max. 2.000 caratteri, spazi inclusi) che sostanzi la scelta dell’esperienza e della sede evidenziando la congruità dell’offerta formativa della stessa con il proprio curriculum di studi. Sono valutate altresì le aspettative e il grado di consapevolezza. b)', ""Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 - 61029 Urbino PU – IT Tel. +39 0722 305327 studerasmus@uniurb.it DISPEA Scienze Geologiche e Ambientali 16 Informatica Applicata 24 Filosofia dell'Informazione 10 *Numero indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Il Dipartimento di Scienze"", 'indicativo che potrebbe variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Il Dipartimento di Studi Umanistici attribuisce il punteggio aggiuntivo secondo i seguenti criteri: Lettera motivazionale (opzionale) – max. 10 punti: predisposizione di una lettera motivazionale (min. 1.000 e max. 2.000 caratteri, spazi inclusi) che sostanzi la', 'variare entro la chiusura del bando e/o se le Università Partner dovessero apportare modifiche agli accordi, anche eventualmente in esito al processo di digitalizzazione in corso di implementazione (Erasmus Without Paper). Il Dipartimento di Economia, Società e Politica attribuisce il punteggio aggiuntivo secondo i seguenti criteri: a) Lettera motivazionale (opzionale) – max. 4 punti: predisposizione di una lettera motivazionale (max. 2.000 caratteri, spazi inclusi) che descriva la scelta dell’esperienza e', 'I documenti di cui al punto a) e b) vanno allegati in fase di presentazione della candidatura (cfr. art. 10). In mancanza di documentazione il punteggio non verrà attribuito. Art. 12.5 – Dipartimento di Scienze Pure e Applicate (DISPeA) Risultano disponibili circa 66 borse di studio, così ripartite: DIPARTIMENTO SCUOLA / CORSO DI LAUREA NUMERO BORSE* DISPEA Conservazione e Restauro 16 Ufficio Mobilità Internazionale Settore Didattica, Post Laurea e Servizi agli Studenti Palazzo Bonaventura – Via Saffi, 2 -']","Il Dipartimento di Scienze Pure e Applicate attribuisce il punteggio aggiuntivo secondo specifici criteri, in particolare per la predisposizione di una lettera motivazionale che evidenzi la congruità dell'offerta formativa con il proprio curriculum di studi. Inoltre, è indicato che il numero di borse di studio potrebbe variare entro la chiusura del bando e in seguito a eventuali modifiche apportate dalle Università Partner a causa del processo di digitalizzazione in corso di implementazione (Erasmus Without Paper).","Il Dipartimento di Scienze Pure e Applicate attribuisce il punteggio aggiuntivo secondo criteri specifici, come la predisposizione di una lettera motivazionale che evidenzi la congruità dell'offerta formativa con il curriculum di studi dello studente.",0.8571428571428571,0.0,0.99999999998
ingestion.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fitz # PyMuPDF
2
+ import re
3
+ from semantic_chunking import SemanticChunker
4
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
5
+ from models import Chunk
6
+ import os
7
+
8
+ def extract_text_by_page(pdf_path: str) -> list[str]:
9
+ """Extract text per page, stripping repeated headers/footers heuristically."""
10
+ if hasattr(pdf_path, "read"): # file-like object from Streamlit uploader
11
+ file_bytes = pdf_path.read()
12
+ doc = fitz.open(stream=file_bytes, filetype="pdf")
13
+ else:
14
+ doc = fitz.open(pdf_path)
15
+ pages = [page.get_text() for page in doc]
16
+ return pages
17
+
18
+ def clean_page_text(text: str) -> str:
19
+ """
20
+ Clean raw PDF text:
21
+ - Rejoin hyphenated line-breaks (e.g. 'documenta-\ntion' → 'documentation')
22
+ - Collapse mid-sentence line breaks (single \n inside a sentence)
23
+ - Normalize whitespace
24
+ """
25
+ # Rejoin words broken across lines with a hyphen
26
+ text = re.sub(r"-\n(\w)", r"\1", text)
27
+ # Single newline mid-sentence → space (keep double newlines as paragraph breaks)
28
+ text = re.sub(r"(?<!\n)\n(?!\n)", " ", text)
29
+ # Collapse extra whitespace
30
+ text = re.sub(r" {2,}", " ", text)
31
+ return text.strip()
32
+
33
+ def get_full_text(pages: list[str]) -> str:
34
+ """Combine cleaned pages into a single text blob."""
35
+ full_text = " ".join(pages)
36
+ return full_text
37
+
38
+ def get_semantic_chunks(text: list[str], source_filename: str) -> list[Chunk]:
39
+ chunker = SemanticChunker(
40
+ model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2",
41
+ similarity_threshold=0.65,
42
+ max_chunk_size=500,
43
+ )
44
+ chunks = chunker.semantic_chunk(text)
45
+ final_chunks = []
46
+ for i, chunk in enumerate(chunks):
47
+ final_chunks.append(Chunk(
48
+ text=chunk,
49
+ chunk_index=i,
50
+ source_filename=source_filename,
51
+ chunk_method="semantic",
52
+ char_count=len(chunk)
53
+ ))
54
+ final_chunks = [chunk for chunk in final_chunks if chunk.char_count > 50]
55
+ print(f"Total chunks created: {len(final_chunks)}")
56
+
57
+ return final_chunks
58
+
59
+ def get_recursive_chunks(text: str, source_filename: str) -> list[Chunk]:
60
+ splitter = RecursiveCharacterTextSplitter(
61
+ chunk_size=512, # tokens or characters depending config
62
+ chunk_overlap=70
63
+ )
64
+ chunks = splitter.split_text(text)
65
+ print(f"Total chunks created: {len(chunks)}")
66
+ final_chunks = []
67
+ for i, chunk in enumerate(chunks):
68
+ final_chunks.append(Chunk(
69
+ text=chunk,
70
+ chunk_index=i,
71
+ source_filename=source_filename,
72
+ chunk_method="recursive",
73
+ char_count=len(chunk)
74
+ ))
75
+ return final_chunks
76
+
77
+ def get_chunks(path: str, method: str = "semantic") -> list[Chunk]:
78
+ source_filename = os.path.basename(path)
79
+ pages = extract_text_by_page(path)
80
+ cleaned_pages = [clean_page_text(page) for page in pages]
81
+ text=get_full_text(cleaned_pages)
82
+ if method == "semantic":
83
+ return get_semantic_chunks(text, source_filename)
84
+ elif method == "recursive":
85
+ return get_recursive_chunks(text, source_filename)
86
+ else:
87
+ raise ValueError(f"Unknown chunking method: {method}")
memory.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from clients import client
2
+
3
+ max_messages = 6 # Max messages to keep in memory
4
+
5
+ def summarize(messages: list[dict], existing_summary) -> str:
6
+ """Summarize a list of messages into a single string."""
7
+ conversation = "\n".join([f"{msg['role']}: {msg['content']}" for msg in messages])
8
+ prompt= f"Existing summary: {existing_summary}\n\nNew conversation:\n{conversation}\n\nUpdate the summary to include the new conversation while keeping it concise."
9
+ response = client.chat.completions.create(
10
+ model="gpt-4o-mini",
11
+ messages=[
12
+ {"role": "system", "content": "You are a helpful assistant that summarizes conversations."},
13
+ {"role": "user", "content": prompt}
14
+ ]
15
+ )
16
+ return response.choices[0].message.content
17
+
18
+
19
+ def update_memory(messages:list, summary: str) -> tuple[list, str]:
20
+ """Update the memory summary with new messages."""
21
+ if len(messages) > max_messages:
22
+ old_messages = messages[:-max_messages//2]
23
+ summary = summarize(old_messages, summary)
24
+ messages = messages[-max_messages//2:]
25
+ return messages, summary
26
+
27
+ def prompt_with_memory(query: str, chunks: list[str], summary: str, messages: list) -> list[dict]:
28
+ relevant_chunks = "\n\n".join(chunks)
29
+ system_content = "You are a precise legal document assistant. Answer strictly based on the provided context. If the answer is not in the context, say: 'This information is not found in the provided document.'"
30
+ if summary:
31
+ system_content += f"\n\nSummary of earlier conversation:\n{summary}"
32
+ return [
33
+ {"role": "system", "content": system_content},
34
+ *messages,
35
+ {"role": "user", "content": f"Context:\n{relevant_chunks}\n\nQuestion: {query}"}
36
+ ]
models.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class Chunk:
5
+ text: str
6
+ chunk_index: int
7
+ source_filename: str
8
+ chunk_method: str
9
+ char_count: int
10
+ summary: str = "" # Optional summary field for future use
11
+ embedding: list[float] = None # To be filled after embedding
12
+ sparse_embedding: dict = None # To be filled after sparse embedding
13
+
pipeline.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ingestion import get_chunks
2
+ from enrichment import add_summary
3
+ from storage import store_chunks
4
+ from qdrant_client.models import Filter, FieldCondition, MatchValue
5
+ from dotenv import load_dotenv
6
+ import os
7
+ load_dotenv()
8
+ from clients import qdrant_client
9
+ from retrieval import retrieve
10
+ from prompt import get_answer
11
+
12
+ COLLECTION_NAME = "rag_documents"
13
+
14
+ def verify_file_existance_in_qdrant(collection_name: str, source_filename: str, chunk_method: str) -> bool:
15
+ """Check if a file has already been processed and stored in Qdrant and by which chunking method."""
16
+ try:
17
+ points, _ = qdrant_client.scroll(
18
+ collection_name=collection_name,
19
+ scroll_filter=Filter(
20
+ must=[
21
+ FieldCondition(
22
+ key="source_filename",
23
+ match=MatchValue(value=source_filename),
24
+
25
+ ),
26
+ FieldCondition(
27
+ key="chunk_method",
28
+ match=MatchValue(value=chunk_method),
29
+ )
30
+ ]
31
+ ),
32
+ limit=1
33
+ )
34
+ return len(points) > 0
35
+ except Exception as e:
36
+ print(f"Error checking file existence in Qdrant: {e}")
37
+ return False
38
+
39
+ def process_document(path: str, method: str = "semantic"):
40
+ """Full pipeline to process a document and store it in Qdrant."""
41
+ filename = os.path.basename(path)
42
+ if verify_file_existance_in_qdrant(COLLECTION_NAME, filename, method):
43
+ print(f"Document '{filename}' with chunking method '{method}' already exists. Skipping processing.")
44
+ else:
45
+ print(f"Processing document: {path}")
46
+ chunks = get_chunks(path, method)
47
+ print("Storing chunks in Qdrant...")
48
+ store_chunks(chunks, COLLECTION_NAME)
49
+ print("Document processing complete.")
prompt.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from clients import client
2
+
3
+ def generate_prompt(query: str, retrieved_chunks: list[str]) -> str:
4
+ """Generate a prompt for the LLM using the retrieved chunks."""
5
+ context = "\n\n".join(retrieved_chunks)
6
+ messages = [
7
+ {
8
+ "role": "system",
9
+ "content": """You are a precise document assistant. Your job is to answer questions strictly based on the provided context extracted from documents.
10
+
11
+ Rules:
12
+ - Only use information present in the context
13
+ - If the answer is not in the context, say explicitly: "This information is not found in the provided document."
14
+ - Be concise but complete
15
+ - When referencing specific clauses or articles, mention them explicitly
16
+ - Never make up information"""
17
+ },
18
+ {
19
+ "role": "user",
20
+ "content": f"""Context:
21
+ {context}
22
+
23
+ Question: {query}
24
+
25
+ Answer based strictly on the context above:"""
26
+ }
27
+ ]
28
+ return messages
29
+
30
+ def generate_response_stream(messages: list[dict]) :
31
+ """Generate a response from the LLM given a list of messages."""
32
+ response = client.chat.completions.create(
33
+ model="gpt-4o-mini",
34
+ messages=messages,
35
+ temperature=0.7,
36
+ stream=True
37
+ )
38
+ for chunk in response:
39
+ delta= chunk.choices[0].delta.content
40
+ if delta:
41
+ yield delta
42
+
43
+ def generate_response(messages: list[dict]) -> str:
44
+ """Generate a response from the LLM given a list of messages."""
45
+ response = client.chat.completions.create(
46
+ model="gpt-4o-mini",
47
+ messages=messages,
48
+ temperature=0.7,
49
+ )
50
+ return response.choices[0].message.content
51
+
52
+ def get_answer(query: str, retrieved_chunks: list[str]) -> str:
53
+ """Get an answer for a query using the retrieved chunks."""
54
+ prompt = generate_prompt(query, retrieved_chunks)
55
+ response = generate_response_stream(prompt)
56
+ print(f"Query: {query}\nAnswer: {response}\n")
57
+ print ("Context used:")
58
+ for i, chunk in enumerate(retrieved_chunks, start=1):
59
+ print(f" {i}. {chunk}")
60
+ return response
61
+
62
+ def get_answer_non_streaming(query: str, retrieved_chunks: list[str]) -> str:
63
+ """Get an answer for a query using the retrieved chunks."""
64
+ prompt = generate_prompt(query, retrieved_chunks)
65
+ response = generate_response(prompt)
66
+ print(f"Query: {query}\nAnswer: {response}\n")
67
+ print ("Context used:")
68
+ for i, chunk in enumerate(retrieved_chunks, start=1):
69
+ print(f" {i}. {chunk}")
70
+ return response
requirements.txt ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ accelerate==1.13.0
2
+ aiofiles==24.1.0
3
+ aiohappyeyeballs==2.6.1
4
+ aiohttp==3.13.5
5
+ aiosignal==1.4.0
6
+ altair==6.0.0
7
+ annotated-doc==0.0.4
8
+ annotated-types==0.7.0
9
+ anyio==4.12.1
10
+ appdirs==1.4.4
11
+ appnope==0.1.4
12
+ asttokens==3.0.1
13
+ attrs==26.1.0
14
+ backcall==0.2.0
15
+ beautifulsoup4==4.14.3
16
+ bleach==6.3.0
17
+ blinker==1.9.0
18
+ blis==1.3.3
19
+ brotli==1.2.0
20
+ cachetools==7.0.5
21
+ catalogue==2.0.10
22
+ certifi==2026.2.25
23
+ cffi==2.0.0
24
+ charset-normalizer==3.4.6
25
+ click==8.3.1
26
+ cloudpathlib==0.23.0
27
+ cohere==5.21.1
28
+ comm==0.2.3
29
+ confection==0.1.5
30
+ contourpy==1.3.3
31
+ cryptography==46.0.5
32
+ cycler==0.12.1
33
+ cymem==2.0.13
34
+ dataclasses-json==0.6.7
35
+ datasets==4.8.4
36
+ debugpy==1.8.20
37
+ decorator==5.2.1
38
+ defusedxml==0.7.1
39
+ Deprecated==1.3.1
40
+ dill==0.4.1
41
+ diskcache==5.6.3
42
+ distro==1.9.0
43
+ docopt==0.6.2
44
+ docstring_parser==0.17.0
45
+ dotenv==0.9.9
46
+ emoji==2.15.0
47
+ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
48
+ et_xmlfile==2.0.0
49
+ executing==2.2.1
50
+ faiss-cpu==1.13.2
51
+ fastapi==0.135.2
52
+ fastavro==1.12.1
53
+ fastembed==0.8.0
54
+ fastjsonschema==2.21.2
55
+ ffmpy==1.0.0
56
+ filelock==3.25.2
57
+ filetype==1.2.0
58
+ flatbuffers==25.12.19
59
+ fonttools==4.62.1
60
+ frozenlist==1.8.0
61
+ fsspec==2026.2.0
62
+ gitdb==4.0.12
63
+ GitPython==3.1.46
64
+ google-api-core==2.30.0
65
+ google-auth==2.49.1
66
+ google-cloud-vision==3.12.1
67
+ googleapis-common-protos==1.73.0
68
+ gradio==6.10.0
69
+ gradio_client==2.4.0
70
+ groovy==0.1.2
71
+ grpcio==1.78.0
72
+ grpcio-status==1.78.0
73
+ h11==0.16.0
74
+ h2==4.3.0
75
+ hf-gradio==0.3.0
76
+ hf-xet==1.4.2
77
+ hpack==4.1.0
78
+ html5lib==1.1
79
+ httpcore==1.0.9
80
+ httpx==0.28.1
81
+ httpx-sse==0.4.3
82
+ huggingface_hub==1.7.2
83
+ hyperframe==6.1.0
84
+ idna==3.11
85
+ installer==0.7.0
86
+ instructor==1.15.1
87
+ ipykernel==7.2.0
88
+ ipython==8.12.3
89
+ ipython_pygments_lexers==1.1.1
90
+ jedi==0.19.2
91
+ Jinja2==3.1.6
92
+ jiter==0.13.0
93
+ joblib==1.5.3
94
+ jsonpatch==1.33
95
+ jsonpointer==3.1.1
96
+ jsonschema==4.26.0
97
+ jsonschema-specifications==2025.9.1
98
+ jupyter_client==8.8.0
99
+ jupyter_core==5.9.1
100
+ jupyterlab_pygments==0.3.0
101
+ kiwisolver==1.5.0
102
+ langchain==1.2.13
103
+ langchain-classic==1.0.3
104
+ langchain-community==0.4.1
105
+ langchain-core==1.2.23
106
+ langchain-openai==1.1.12
107
+ langchain-text-splitters==1.1.1
108
+ langdetect==1.0.9
109
+ langgraph==1.1.3
110
+ langgraph-checkpoint==4.0.1
111
+ langgraph-prebuilt==1.0.8
112
+ langgraph-sdk==0.3.12
113
+ langsmith==0.7.22
114
+ llvmlite==0.46.0
115
+ loguru==0.7.3
116
+ lxml==6.0.2
117
+ Markdown==3.10.2
118
+ markdown-it-py==4.0.0
119
+ MarkupSafe==3.0.3
120
+ marshmallow==3.26.2
121
+ matplotlib==3.10.8
122
+ matplotlib-inline==0.2.1
123
+ mdurl==0.1.2
124
+ mistune==3.2.0
125
+ ml_dtypes==0.5.4
126
+ mmh3==5.2.1
127
+ mpmath==1.3.0
128
+ msoffcrypto-tool==6.0.0
129
+ multidict==6.7.1
130
+ multiprocess==0.70.19
131
+ murmurhash==1.0.15
132
+ mypy_extensions==1.1.0
133
+ narwhals==2.18.1
134
+ nbclient==0.10.4
135
+ nbconvert==7.17.0
136
+ nbformat==5.10.4
137
+ nest-asyncio==1.6.0
138
+ networkx==3.6.1
139
+ numba==0.64.0
140
+ numpy==2.4.3
141
+ olefile==0.47
142
+ ollama==0.6.1
143
+ onnx==1.20.1
144
+ onnxruntime==1.24.4
145
+ openai==2.30.0
146
+ opencv-python==4.13.0.92
147
+ openpyxl==3.1.5
148
+ orjson==3.11.7
149
+ ormsgpack==1.12.2
150
+ packaging==26.0
151
+ pandas==3.0.1
152
+ pandocfilters==1.5.1
153
+ parso==0.8.6
154
+ pdf2image==1.17.0
155
+ pdfminer.six==20260107
156
+ pexpect==4.9.0
157
+ pi_heif==1.3.0
158
+ pickleshare==0.7.5
159
+ pikepdf==10.5.1
160
+ pillow==12.1.1
161
+ pipreqs==0.5.0
162
+ platformdirs==4.9.4
163
+ portalocker==3.2.0
164
+ preshed==3.0.12
165
+ prompt_toolkit==3.0.52
166
+ propcache==0.4.1
167
+ proto-plus==1.27.1
168
+ protobuf==6.33.6
169
+ psutil==7.2.2
170
+ ptyprocess==0.7.0
171
+ pure_eval==0.2.3
172
+ py_rust_stemmers==0.1.5
173
+ pyarrow==23.0.1
174
+ pyasn1==0.6.3
175
+ pyasn1_modules==0.4.2
176
+ pycparser==3.0
177
+ pydantic==2.12.5
178
+ pydantic-settings==2.13.1
179
+ pydantic_core==2.41.5
180
+ pydeck==0.9.1
181
+ pydub==0.25.1
182
+ Pygments==2.19.2
183
+ PyMuPDF==1.27.2.2
184
+ pypandoc_binary==1.17
185
+ pyparsing==3.3.2
186
+ pypdf==6.9.1
187
+ pypdfium2==5.6.0
188
+ python-dateutil==2.9.0.post0
189
+ python-docx==1.2.0
190
+ python-dotenv==1.2.2
191
+ python-iso639==2026.1.31
192
+ python-magic==0.4.27
193
+ python-multipart==0.0.22
194
+ python-oxmsg==0.0.2
195
+ python-pptx==1.0.2
196
+ pytz==2026.1.post1
197
+ PyYAML==6.0.3
198
+ pyzmq==27.1.0
199
+ qdrant-client==1.17.1
200
+ ragas==0.4.3
201
+ RapidFuzz==3.14.3
202
+ referencing==0.37.0
203
+ regex==2026.2.28
204
+ requests==2.32.5
205
+ requests-toolbelt==1.0.0
206
+ rich==14.3.3
207
+ rpds-py==0.30.0
208
+ safehttpx==0.1.7
209
+ safetensors==0.7.0
210
+ scikit-learn==1.8.0
211
+ scikit-network==0.33.5
212
+ scipy==1.17.1
213
+ semantic-version==2.10.0
214
+ semantic_chunking==0.1.1
215
+ sentence-transformers==5.3.0
216
+ setuptools==82.0.1
217
+ shellingham==1.5.4
218
+ six==1.17.0
219
+ smart_open==7.5.1
220
+ smmap==5.0.3
221
+ sniffio==1.3.1
222
+ soupsieve==2.8.3
223
+ spacy==3.8.11
224
+ spacy-legacy==3.0.12
225
+ spacy-loggers==1.0.5
226
+ SQLAlchemy==2.0.49
227
+ srsly==2.5.2
228
+ stack-data==0.6.3
229
+ starlette==0.52.1
230
+ sympy==1.14.0
231
+ tenacity==9.1.4
232
+ thinc==8.3.11
233
+ threadpoolctl==3.6.0
234
+ tiktoken==0.12.0
235
+ timm==1.0.25
236
+ tinycss2==1.4.0
237
+ tokenizers==0.22.2
238
+ toml==0.10.2
239
+ tomlkit==0.13.3
240
+ torch==2.10.0
241
+ torchvision==0.25.0
242
+ tornado==6.5.5
243
+ tqdm==4.67.3
244
+ traitlets==5.14.3
245
+ transformers==5.3.0
246
+ typer==0.24.1
247
+ typer-slim==0.24.0
248
+ types-requests==2.33.0.20260327
249
+ typing-inspect==0.9.0
250
+ typing-inspection==0.4.2
251
+ typing_extensions==4.15.0
252
+ unstructured==0.21.5
253
+ unstructured-client==0.42.10
254
+ unstructured.pytesseract==0.3.15
255
+ unstructured_inference==1.5.2
256
+ urllib3==2.6.3
257
+ uuid_utils==0.14.1
258
+ uvicorn==0.42.0
259
+ wasabi==1.1.3
260
+ wcwidth==0.6.0
261
+ weasel==0.4.3
262
+ webencodings==0.5.1
263
+ wrapt==1.17.3
264
+ xlrd==2.0.2
265
+ xlsxwriter==3.2.9
266
+ xxhash==3.6.0
267
+ yarg==0.1.9
268
+ yarl==1.23.0
269
+ zstandard==0.25.0
retrieval.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from clients import qdrant_client, client, sparse_model, cohere_client
2
+ from qdrant_client.models import Prefetch, Fusion, SparseVector, models
3
+
4
+ def embed_query_dense(query: str) -> list[float]:
5
+ """Embed a query string using OpenAI embeddings."""
6
+ response = client.embeddings.create(
7
+ model="text-embedding-3-small",
8
+ input=query
9
+ )
10
+ return response.data[0].embedding
11
+
12
+ def embed_query_sparse(query: str) -> SparseVector:
13
+ """Embed a query string using the sparse embedding model."""
14
+ result = list(sparse_model.embed([query]))[0]
15
+ return SparseVector(
16
+ indices=result.indices.tolist(),
17
+ values=result.values.tolist()
18
+ )
19
+
20
+ from qdrant_client import models
21
+
22
+ def rrf_search(collection_name: str, query: str, top_k: int = 5) -> list[str]:
23
+ query_dense = embed_query_dense(query)
24
+ query_sparse = embed_query_sparse(query)
25
+
26
+ results = qdrant_client.query_points(
27
+ collection_name=collection_name,
28
+ prefetch=[
29
+ models.Prefetch(
30
+ query=query_sparse,
31
+ using="sparse",
32
+ limit=top_k * 2
33
+ ),
34
+ models.Prefetch(
35
+ query=query_dense,
36
+ using="dense",
37
+ limit=top_k * 2
38
+ ),
39
+ ],
40
+ query=models.FusionQuery(fusion=models.Fusion.RRF),
41
+ limit=top_k
42
+ )
43
+ return [result.payload["text"] for result in results.points]
44
+
45
+ def rerank_results(query: str, texts: list[str], top_k: int = 5) -> list[str]:
46
+ """Rerank retrieved chunks using a cross-encoder model."""
47
+ ranker= cohere_client.rerank(
48
+ model="rerank-v3.5",
49
+ query=query,
50
+ documents=texts,
51
+ top_n=top_k
52
+ )
53
+ return [texts[result.index] for result in ranker.results] # Return top_k results as-is for now
54
+
55
+ def retrieve(collection_name: str, query: str, top_k: int = 5) -> list[str]:
56
+ """Retrieve relevant chunks for a query."""
57
+ initial_results = rrf_search(collection_name, query, top_k*2) # Get more results for reranking
58
+ reranked_results = rerank_results(query, initial_results, top_k)
59
+ return reranked_results
storage.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from qdrant_client import QdrantClient
2
+ from dotenv import load_dotenv
3
+ import os
4
+ load_dotenv()
5
+ from models import Chunk
6
+ import uuid
7
+ from qdrant_client.models import VectorParams, Distance, SparseVectorParams
8
+ from qdrant_client.models import PointStruct, SparseVector
9
+ from clients import client, qdrant_client, sparse_model
10
+
11
+
12
+ def embed_chunks(chunks: list[Chunk]) -> list[Chunk]:
13
+ """Add embeddings to a list of chunks using a single batched API call."""
14
+ texts = [chunk.text for chunk in chunks]
15
+ response = client.embeddings.create(
16
+ model="text-embedding-3-small",
17
+ input=texts
18
+ )
19
+ for chunk, embedding_obj in zip(chunks, response.data):
20
+ chunk.embedding = embedding_obj.embedding
21
+ return chunks
22
+
23
+ def sparse_embed_chunks(chunks: list[Chunk]) -> list[Chunk]:
24
+ """Add sparse embeddings to a list of chunks in one batched call."""
25
+ texts = [chunk.text for chunk in chunks]
26
+ results = list(sparse_model.embed(texts))
27
+ for chunk, result in zip(chunks, results):
28
+ chunk.sparse_embedding = {
29
+ "indices": result.indices.tolist(),
30
+ "values": result.values.tolist()
31
+ }
32
+ return chunks
33
+
34
+ def create_collection(collection_name: str):
35
+ """Create a Qdrant collection if it doesn't exist."""
36
+ existing_collections = qdrant_client.get_collections().collections
37
+ if collection_name not in [col.name for col in existing_collections]:
38
+ qdrant_client.create_collection(
39
+ collection_name=collection_name,
40
+ vectors_config={
41
+ "dense": VectorParams(
42
+ size=1536, # Size of the embedding vector
43
+ distance=Distance.COSINE # Distance metric for similarity search
44
+ )},
45
+ sparse_vectors_config={
46
+ "sparse": SparseVectorParams()
47
+ }
48
+ )
49
+ print (f"Collection '{collection_name}' created.")
50
+ else:
51
+ print (f"Collection '{collection_name}' already exists.")
52
+
53
+ for field in ("source_filename", "chunk_method"):
54
+ try:
55
+ qdrant_client.create_payload_index(
56
+ collection_name=collection_name,
57
+ field_name=field,
58
+ field_schema="keyword"
59
+ )
60
+ except Exception:
61
+ pass # Index already exists
62
+
63
+ def upsert_chunks(chunks: list[Chunk], collection_name: str):
64
+ batch_size = 50
65
+ for i in range(0, len(chunks), batch_size):
66
+ batch = chunks[i:i + batch_size]
67
+ points = []
68
+ for chunk in batch:
69
+ point = PointStruct(
70
+ id=str(uuid.uuid5(uuid.NAMESPACE_DNS, f"{chunk.source_filename}_{chunk.chunk_index}")),
71
+ vector={
72
+ "dense": chunk.embedding,
73
+ "sparse": SparseVector(
74
+ indices=chunk.sparse_embedding["indices"],
75
+ values=chunk.sparse_embedding["values"]
76
+ )
77
+ },
78
+ payload={
79
+ "text": chunk.text,
80
+ "source_filename": chunk.source_filename,
81
+ "chunk_method": chunk.chunk_method,
82
+ "char_count": chunk.char_count,
83
+ "summary": chunk.summary
84
+ }
85
+ )
86
+ points.append(point)
87
+ qdrant_client.upsert(collection_name=collection_name, points=points)
88
+ print(f"Upserted batch {i//batch_size + 1}/{(len(chunks)-1)//batch_size + 1}")
89
+ print(f"Stored {len(chunks)} chunks in collection '{collection_name}'.")
90
+
91
+ def store_chunks(chunks: list[Chunk], collection_name: str):
92
+ """Embed and store chunks in Qdrant."""
93
+ create_collection(collection_name)
94
+ print("Dense Embedding chunks...")
95
+ embedded_chunks = embed_chunks(chunks)
96
+ print("Sparse Embedding chunks...")
97
+ sparse_embedded_chunks = sparse_embed_chunks(embedded_chunks)
98
+ print("Upserting chunks to Qdrant...")
99
+ upsert_chunks(sparse_embedded_chunks, collection_name)