Repository: TabbyML/tabby
File: ee/tabby-webserver/src/service/answer.rs (Rust)

Code before:
        r#"You are given a user question, and please write clean, concise and accurate answer to the question. You will be given a set of related contexts to the question, each starting with a reference number like [[citation:x]], where x is a number. Please use the context and cite the context at the end of each sentence if applicable.

Your answer must be correct, accurate and written by an expert using an unbiased and professional tone. Please limit to 1024 tokens. Do not give any information that is not related to the question, and do not repeat. Say "information is missing on" followed by the related topic, if the given context do not provide sufficient information.

Please cite the contexts with the reference numbers, in the format [[citation:x]]. If a sentence comes from multiple contexts, please list all applicable citations, like [[citation:3]][[citation:5]]. Other than code and specific names and citations, your answer must be written in the same language as the question.

Here are the set of contexts:

{context}

Remember, don't blindly repeat the contexts verbatim. When possible, give code snippet to demonstrate the answer. And here is the user question:

{user_input}
"#
    )
}

/// Combine code snippets from search results rather than utilizing multiple hits: Presently, there is only one rule: if the number of lines of code (LoC) is less than 200, and there are multiple hits (number of hits > 1), include the entire file.
pub async fn merge_code_snippets(
    repository: Option<Repository>,
    hits: Vec<CodeSearchHit>,
) -> Vec<CodeSearchHit> {
    let repository = match repository {
        Some(repo) => repo,
        None => return hits,
    };

    // group hits by filepath
    let mut file_hits: HashMap<String, Vec<CodeSearchHit>> = HashMap::new();
    for hit in hits.clone().into_iter() {
        let key = format!("{}-{}", repository.source_id, hit.doc.filepath);
        file_hits.entry(key).or_default().push(hit);
    }

    let mut result = Vec::with_capacity(file_hits.len());

    for (_, file_hits) in file_hits {
        if file_hits.len() > 1 {
            // construct the full path to the file
            let path: PathBuf = repository.dir.join(&file_hits[0].doc.filepath);
            let all_lines = match read_file_content(&path) {
                Ok(lines) => lines,
                Err(e) => {
                    warn!("Error reading file {}: {}", path.display(), e);
                    //cannot read the file, just extend the hits
                    result.extend(file_hits);
                    continue;
                }
            };

            if !all_lines.is_empty() {

Review comment (suggestion):
```suggestion
    let Some(repository) = repository else {
        return hits;
    };
```

Code after:
        .collect();

    let context = citations.join("\n\n");

    format!(
        r#"You are given a user question, and please write clean, concise and accurate answer to the question. You will be given a set of related contexts to the question, each starting with a reference number like [[citation:x]], where x is a number. Please use the context and cite the context at the end of each sentence if applicable.

Your answer must be correct, accurate and written by an expert using an unbiased and professional tone. Please limit to 1024 tokens. Do not give any information that is not related to the question, and do not repeat. Say "information is missing on" followed by the related topic, if the given context do not provide sufficient information.

Please cite the contexts with the reference numbers, in the format [[citation:x]]. If a sentence comes from multiple contexts, please list all applicable citations, like [[citation:3]][[citation:5]]. Other than code and specific names and citations, your answer must be written in the same language as the question.

Here are the set of contexts:

{context}

Remember, don't blindly repeat the contexts verbatim. When possible, give code snippet to demonstrate the answer. And here is the user question:

{user_input}
"#
    )
}

/// Combine code snippets from search results rather than utilizing multiple hits: Presently, there is only one rule: if the number of lines of code (LoC) is less than 200, and there are multiple hits (number of hits > 1), include the entire file.
pub async fn merge_code_snippets(
    repository: Option<Repository>,
    hits: Vec<CodeSearchHit>,
) -> Vec<CodeSearchHit> {
    let Some(repository) = repository else {
        return hits;
    };

    // group hits by filepath
    let mut file_hits: HashMap<String, Vec<CodeSearchHit>> = HashMap::new();
    for hit in hits.clone().into_iter() {
        let key = format!("{}-{}", repository.source_id, hit.doc.filepath);
        file_hits.entry(key).or_default().push(hit);
    }

    let mut result = Vec::with_capacity(file_hits.len());

    for (_, file_hits) in file_hits {
        if file_hits.len() > 1 {
            // construct the full path to the file
            let path: PathBuf = repository.dir.join(&file_hits[0].doc.filepath);
            let file_content = match read_file_content(&path) {
                Some(lines) => lines,
                None => {
                    //cannot read the file, just extend the hits
                    result.extend(file_hits);
                    continue;
                }